Spring-Ioc基础知识

1 简介

1.1 什么叫Spring

  • 狭义的Spring: Spring Framework
  • 广义的Spring:指的是整个Spring生态,包含 Spring Framework,Spring boot,Spring cloud,Spring Security 等在内的一站式开发框架。

1.2 Spring架构图


2 初识Spring IOC

  • IOC (Inversion of Control): 控制反转,是一种设计理念。将实例对象的权利转移到IOC容器管理,使用时不再需要new对象,直接在IOC容器里面拿。
  • DI (dependency injection): 依赖注入,是实现IOC理念的一种方式。
  • 核心作用就是:由Spring IOC容器创建和管理对象(Beans)

2.1 传统方式

当使用一个类的时候都需要先去实例这个类对象,每多一个,多实例一个,这样的方式代码耦合性相当高,当需求改变时,需要修改代码中对应的实例对象。

2.2 IOC思想

全部统一由一个容器去管理这些需要的类,当需要使用时,直接在容器中拿,这样减少了代码的耦合性。

2.3 DI实现

DI依赖注入,在容器中可以将类中需要的其他类注入。

3 SpringIOC初体验

3.1 maven导入

1
2
3
4
5
6
<!--spring-context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>

3.2 准备entity类

每一个entity类都需要遵循javaBean规范,必须书写get和set方法。

3.2.1 woman

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Woman {
/**
* 姓名
*/
private String name;

/**
* 年龄
*/
private int age;

/**
* 外貌
*/
private String outLook;
}

3.2.2 Man

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Man {
/**
* 姓名
*/
private String name;

/**
* 资产
*/
private String fund;

/**
* 心动女生
*/
private Woman woman;
/**
* 方法:示爱
*/
public void proposal(){
System.out.println("这名拥有"+fund+"资产的名字叫"+name+"的男嘉宾向年纪为"
+woman.getAge()+"的外貌是"+woman.getOutLook()+"的"
+woman.getName()+"女士示爱了");
}
}

3.3 书写配置文件

在配置文件中可以添加多个bean

  • id:bean的定义name
  • class:需要ioc管理的entity类路径
  • property:配置参数
  • value:设置基本数据类型的参数
  • ref:引用类型的参数引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 配置Bean参数 -->
<bean id="lili" class="com.moon.entity.Woman">
<property name="name" value="莉莉"/>
<property name="age" value="18"/>
<property name="outLook" value="面容较好的"/>
</bean>
<bean id="jackMa" class="com.moon.entity.Man">
<property name="name" value="杰克马"/>
<property name="fund" value="数百亿"/>
<property name="woman" ref="lili"/>
</bean>
</beans>

3.4 书写测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void springIoc() {
// 获得IOC容器上下文
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 取bean
// 方式一:通过id取bean,需要强转
Woman lili = (Woman) context.getBean("lili");
// 方式二:通过id取bean,传入返回类型,不需要强转
Man jackMa = context.getBean("jackMa", Man.class);

System.out.println(lili);
jackMa.proposal();
}

4 基于XML创建Bean

4.1 基于构造方法

4.1.1 无参构造

默认的就是无参构造

Women在无参构造输出

1
2
3
public Woman() {
System.out.println("无参海选女嘉宾");
}

配置bean

1
2
3
4
5
<bean id="lili" class="com.moon.entity.Woman">
<property name="name" value="莉莉"/>
<property name="age" value="18"/>
<property name="outLook" value="面容较好的"/>
</bean>

创建IOC

1
2
3
public static void main(String[] args) {
new ClassPathXmlApplicationContext("applicationContext.xml");
}

结果

4.1.2 有参数构造

在使用有参构造器创建时,也需要同时将依赖注入。

1
2
3
4
5
<bean id="lili" class="com.moon.entity.Woman">
<constructor-arg name="name" value="莉莉"/>
<constructor-arg name="age" value="18"/>
<constructor-arg name="outLook" value="面容较好的"/>
</bean>

4.2 基于工厂模式

隐藏创建的细节

4.2.1 静态工厂

java静态工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class WomanStaticFactory {
public static Woman selectLili(){
Woman lili = new Woman();
lili.setName("莉莉");
lili.setAge(18);
lili.setOutLook("面容较好的");
return lili;
}
public static Woman selectMary(){
Woman lili = new Woman();
lili.setName("玛丽");
lili.setAge(20);
lili.setOutLook("体态丰满的");
return lili;
}
}

配置静态工厂

1
2
3
<!-- 通过class定位到静态工厂类,使用factory-menthod定位到方法 -->
<bean id="lili" class="com.moon.factory.WomanStaticFactory" factory-method="selectLili"/>
<bean id="mary" class="com.moon.factory.WomanStaticFactory" factory-method="selectMary"/>

4.2.2 工厂实例

java实例工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class WomanFactory {
public Woman selectLili(){
Woman lili = new Woman();
lili.setName("莉莉");
lili.setAge(18);
lili.setOutLook("面容较好的");
return lili;
}
public Woman selectMary(){
Woman lili = new Woman();
lili.setName("玛丽");
lili.setAge(20);
lili.setOutLook("体态丰满的");
return lili;
}
}

配置实例工厂

1
2
3
4
5
6
<!-- 添加工厂的bean(使用工厂类的无参创建) -->
<bean id="factory" class="com.moon.factory.WomanFactory"/>

<!-- 不用使用class去定位,直接用factory-bean定位到一个工厂对象,使用factory-method定位到工厂方法 -->
<bean id="lili" factory-bean="factory" factory-method="selectLili"/>
<bean id="mary" factory-bean="factory" factory-method="selectMary"/>

4.3 配置文件书写规范

1、**<bean/>**标签中的id和name都是用来设置对象在IOC中标识。区别如下:

  • 在**==同一个配置文件====不可以重复==**
  • 如果在不同配置文件中出现相同的==ID==和**==Name====bean==,排序在后面的bean会覆盖前面的==bean==**。
  • 在**==同一个bean==中同时配置了==id====name==,那么==id为容器中的唯一标志==**,而name为别名,如果配置了多个name,那么==name全部是别名==。
  • 如果**==这个bean==只==配置了name==,==没有id==,那么name为唯一标志。如果name配置了多个,那么==第一个name是唯一标志,剩余的name为别名==**。
  • 在一个bean中,name可以写多个标志,id只能设置唯一标志。

2、如果没有配置name和id的话,ioc容器会给bean设置一个默认标识,该标识是bean的class+#数字标识,数字从0开始。

1
com.moon.entity.Woman#0

如过根据标识去获取类,只写了全类名,ioc会去获取全类名+#0的bean,也就是第一个bean。

5 DI依赖注入

在一个类里面需要依赖另一个类,之前使用时是在类中去new另外的类。而使用了spring后,spring使用依赖注入(DI)的方式,将bean或者参数注入到另一个bean中。

  • 注入基本数据类型和字符串时使用 value
  • 注入引用类型,引用其他bean使用 ref

5.1 基于构造器注入

通过构造器注入

和前面的创建一样,通过构造器创建时注入,注入的方法有三种。

  • 通过参数name赋值(常用)

    1
    2
    3
    4
    5
    <bean id="lili" class="com.moon.entity.Woman">
    <constructor-arg name="name" value="莉莉"/>
    <constructor-arg name="age" value="18"/>
    <constructor-arg name="outLook" value="面容较好的"/>
    </bean>
  • 通过下标赋值(下标从0开始,下标对应的属性由构造器决定)

    1
    2
    3
    4
    5
    <bean id="lili" class="com.moon.entity.Woman">
    <constructor-arg index="0" value="莉莉"/>
    <constructor-arg index="1" value="18"/>
    <constructor-arg index="2" value="面容较好的"/>
    </bean>
  • 通过类型赋值

    1
    2
    3
    4
    5
    <bean id="lili" class="com.moon.entity.Woman">
    <constructor-arg type="java.lang.String" value="莉莉"/>
    <constructor-arg type="int" value="18"/>
    <constructor-arg type="java.lang.String" value="面容较好的"/>
    </bean>

5.2 基于Setter方法注入

通过set方法注入,通过该方法,需要确保属性全部有对应的set方法

涉及到的标签是<property>

原理:ioc容器会先去调用bean的无参构造器或者工厂模式去实例一个bean,然后再调用这个bean的set方法,将属性注入。

1
2
3
4
5
6
<bean id="lili" class="com.moon.entity.Woman">
<!--调用set方法注入属性-->
<property name="name" value="莉莉"/>
<property name="age" value="18"/>
<property name="outLook" value="面容较好的"/>
</bean>
  • 注入基本数据类型加String 使用value
  • 注入引用数据类型使用ref来引用

5.2.1 循环依赖

如果出现循环依赖的问题,俩个bean相互依赖,那么就一定需要使用set的方式注入,如果使用构造器方式注入的话,就会出现异常。

原理:在sring中,会先全部实例对应的bean,全部实例号以后,才会对对应的bean进行注入。如果使用构造器注入的话,在实例的时候就需要寻找其他的bean,而此时其他的bean可能还没有实例。

1
2
3
4
5
6
7
8
9
<!-- bean A依赖于B的实例 -->
<bean id="dependencyA" class="com.moon.entity.DependencyA">
<property name="dependencyB" ref="dependencyB"/>
</bean>

<!-- bean B依赖于A的实例 -->
<bean id="dependencyB" class="com.moon.entity.DependencyB">
<property name="dependencyA" ref="dependencyA"/>
</bean>

5.2.2 内部注入

可以在一个bean的property中,将property标签不自闭合,然后在property标签中可以声明一个bean

注意:

  • 内部注入的bean,不会受ioc容器接管,在ioc容器中是取不到这个类的,类似于java的内部类。
  • 内部bean仅作用在这个bean的property中,不归容器所有。

SpringIOC容器在处理inner bean时,只负责创建,不负责管理。

1
2
3
4
5
6
7
8
9
10
11
<bean id="peter" class="com.moon.entity.Man">
<property name="name" value="皮特李"/>
<property name="fund" value="负载累累"/>
<property name="woman">
<bean class="com.moon.entity.Woman">
<property name="name" value="皮特李的秘书"/>
<property name="outLook" value="聪明能干的"/>
<property name="age" value="18"/>
</bean>
</property>
</bean>

5.2.3 数组的注入

数组的注入,可以将property标签不去自闭合,在标签中使用array标签进行该数组的值的赋值

1
2
3
4
5
6
7
8
9
<bean id="fierceMan" class="com.moon.entity.FierceMan">
<property name="clothes">
<array>
<value>背心</value>
<value>人字拖</value>
<value>短裤</value>
</array>
</property>
</bean>

5.2.4 List注入

List的注入和array一样,需要在property标签中引用list标签

默认的实现是ArrayList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<bean id="fierceMan" class="com.moon.entity.FierceMan">
<!--猛男喜欢的电脑颜色-->
<property name="computerColor">
<list value-type="java.lang.String">
<value>粉红色</value>
<value>玫瑰金</value>
</list>
</property>
<!--猛男喜欢的电脑-->
<property name="computers">
<list value-type="com.moon.entity.Computer">
<bean class="com.moon.entity.Computer" p:boxColor="粉红色"/>
</list>
</property>
</bean>

5.2.5 Set注入

和List注入的方式基本一致,需要在property标签中引用set标签

默认的实现类是LinkedHashSet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<bean id="fierceMan" class="com.moon.entity.FierceMan">
<!--猛男喜欢的雌性-->
<property name="femaleSet">
<set value-type="com.moon.entity.Female">
<!--第一种雌性-->
<ref bean="female"/>
<!--第二种雌性-->
<bean class="com.moon.entity.Female">
<property name="age" value="18"/>
<property name="outLook" value="身材好的"/>
</bean>
</set>
</property>
</bean>
<bean id="female" class="com.moon.entity.Female">
<property name="age" value="51~99"/>
<property name="outLook" value="长得匹配"/>
</bean>

5.2.6 Map注入

map的注入和之前一样,在property标签先使用map标签,不同的是map标签下注入的是entry,key的声明是在entry标签的属性上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<bean id="fierceMan" class="com.moon.entity.FierceMan">
<!--猛男喜欢的卡通-->
<property name="cartoonMap">
<map key-type="java.lang.String" value-type="com.moon.entity.Cartoon">
<!--引用已有bean-->
<entry key="1" value-ref="baby"/>
<!--创建内部bean-->
<entry key="2">
<bean class="com.moon.entity.Cartoon">
<property name="cartoonName" value="花园宝宝"/>
</bean>
</entry>
</map>
</property>
</bean>

<bean id="baby" class="com.moon.entity.Cartoon">
<property name="cartoonName" value="天线宝宝"/>
</bean>

5.2.7 Properties注入

在spring配置文件也可以注入prop信息,注入的方式和集合的注入基本类似

1
2
3
4
5
6
7
8
9
10
11
<bean id="fierceMan" class="com.moon.entity.FierceMan">
<!--猛男珍藏数据库-->
<property name="properties">
<props value-type="java.lang.String">
<prop key="driverClassName">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/test</prop>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>

6 扩展命名空间

6.1 c命名空间

xml配置文件头文件中导入c命名空间约束

1
xmlns:c="http://www.springframework.org/schema/c"

c 命名空间的使用就是基于构造器注入的方法,需要bean中有有参构造器

1
2
3
4
5
<bean name="mary3" class="com.moon.entity.Woman"
c:name="玛丽"
c:age="20"
c:outLook="体态丰满的"
/>
1
2
3
4
5
<bean id="jackMa" class="com.moon.entity.Man"
c:name="杰克马"
c:fund="数亿的"
c:woman-ref="mary"
/>

6.2 p命名空间

xml配置文件头文件中导入pmm空间约束

1
xmlns:p="http://www.springframework.org/schema/p"

p命名空间的使用就是基于set方法注入

1
2
3
4
5
<bean id="peter" class="com.moon.entity.Man"
p:name="皮特"
p:fund="数亿的"
p:woman-ref="lili"
/>

7 bean的属性

==scope== 作用域
id、name 定义bean的唯一标识
class bean的全类名
factory-bean 工厂对象
factory-method 工厂方法
lazy-init 懒加载
depends-on 依赖某个实例(在生命周期用到)
==init-methid== Bean初始化执行的方法
==destory-metho== bean销毁时执行的方法
autowire 自动装配(依赖注入)

7.1 Scope属性

bean的作用域

7.1.1 属性值说明

Scpoe 描述
singleton 单例模式创建bean,==默认的==scope就是单例模式
prototype 原型,指定单个bean的实例对象数量为任意多个
request web环境下,每一次独立请求都存在唯一实例,存在单个HTTP请求中,bean 的作用域限于 HTTP请求范围
session web环境下,每一次会话都存在唯一的实例,存在单个的会话中,bean的作用域限于单次的会话范围
application web环境下,这里的作用域时在servletContext上下文中的唯一的实例
websocket web环境下,将单个bean的作用域限定为websocket的生命周期

7.1.2 singleton和prototype的区别

  • singleton的实例对象数量时唯一的,而prototype的实例对象是多个的
  • singleton在容器初始化时就会实例化一个对象放在容器中,而prototype是在使用getBean方法是才会去创建这个bean的实例,每一次的实例都不一样。
  • 效率的不同,singleton的效率会高一些,因为只会实例一次
  • 线程的安全问题,prototype的线程会安全一些

8 bean的生命周期

生命周期就是bean的实例在IOC容器中从创建到销毁的过程

在spring中bean的生命周期很复杂,但是可以简单的理解为以下周期:

  • 实例化
  • 注入属性
  • 调用实现接口方法
  • 初始化
  • 就绪
  • 销毁

8.1 自定义初始化方法

在配置文件中,可以在bean的属性配置中使用init-method来指定自定义的初始化方法

比如在实体类中添加了以下方法:

1
2
3
private void init(){
System.out.println("custom-init");
}

那么就可以在配置文件中去指定该方法为初始化方法

1
<bean id="man" class="com.moon.entity.FierceMan" init-method="init"/>

8.2 自定义销毁方法

销毁方法的自定义和初始化的一样

在实体类添加以下销毁方法:

1
2
3
private void destroy(){
System.out.println("custom-destroy");
}

在配置文件中配置:

1
<bean id="man" class="com.moon.entity.FierceMan" destroy-method="destroy"/>

8.3 BeanPostProcessor的实现

如果实现了该接口,那么在容器初始化bean的前后会调用BeanPostProcessor的对应方法

实现自己的BeanPostProcessor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 只判断bean的类型为FierceMan
if (bean instanceof FierceMan) {
System.out.println("BeanPostProcessor之前");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof FierceMan) {
System.out.println("BeanPostProcessor之后");
}
return bean;
}
}

在配置文件中配置

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--bean-->
<bean id="man" class="com.moon.entity.FierceMan" init-method="init" destroy-method="destroy"/>
<!--BeanPostProcessor-->
<bean id="beanPostProcessor" class="com.moon.entity.MyBeanPostProcessor"/>
</beans>

结果

9 基于注解开发

好处:

  • 摆脱繁琐的xml文件的配置和属性注入

  • 可读性好,声明式的开发风格更符合中小型项目,很适合轻量级的开发

使用注解的前提,需要在配置文件中开启组件扫描

1
2
3
4
5
<!-- 需要导入xml头文件 -->
<context:component-scan base-package="com.moon">
<!--排除不需要扫描的bean目录或者bean-->
<context:exclude-filter type="regex" expression="com.moon.pojo.*"/>
</context:component-scan>

9.1 注解的分类

  • 根据**==Bean的类型==**分类:来标注和管理bean

    @Component : 组件注解,是一个通用注解,意思是交给IOC容器来管理

    @Repository : 一般标注在Dao层/持久层,也是把类交给IOC容器管理

    @Service : 标注在业务层/逻辑层

    @Controller : 在Web环境下标注在控制层/控制器类上

  • 根据如何==注入属性==来分类

    • 按照类型

      @Autowired由IOC容器按照管理bean的类型去注入

      @Inject基于JSR-330(java依赖注入标准的330号文件),也是通过类型去注入,需要额外引入依赖

    • 按名称

      @Named : 基于JSR-330(java依赖注入标准的330号文件),一般和Inject配合一起使用,也需要引入依赖

      @Qualifier : 和Autowired配合使用,通过name指定对应的bean

      @Resource : 基于JSR-250,先按照名称注入,如果没有再按照类型注入

  • 元数据注解:辅助容器更好的管理bean

    @Primary : 主要用在根据类型装配的时候,ioc容器存在多个统一类型的Bean造成装配失败,标识当前的类为主要bean,在多个bean冲突的时候,会优先注入该类。

    1
    2
    3
    4
    5
    6
    7
    8
    @Repository
    @Primary
    public class GardenBabyCartoonDao implements CartoonDao{
    @Override
    public void rentCD() {
    System.out.println("我租到了花园宝宝的盘");
    }
    }

    @PostConstruct相当于xml配置文件中的init-method的自定义初始化方法

    1
    2
    3
    4
    @PostConstruct
    public void annotationInit(){
    System.out.println("猛男爱看的动漫被初始化了");
    }

    @PreDestroy相当于xml配置文件中的destroy-method的自定义销毁方法

    1
    2
    3
    4
    @PreDestroy
    public void annotationDestroy(){
    System.out.println("猛男爱看的动漫被销毁了");
    }

    @Scope设定一个bean的作用域属性,默认的情况下是singlten,标识在类上

    1
    2
    3
    @Service
    @Scope("prototype")
    public class CartoonService {}

    读取外部的配置文件

    1
    2
    user=root
    password=123

    在spring的配置中添加如下

    1
    2
    <!--让IOC容器读取外部文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    使用Value注解去换取配置文件的值

    1
    2
    3
    4
    5
    @Value("${user}")
    private String url;

    @Value("${password}")
    private String password;

    @Value为类中的属性注入静态数据,如果引用外部的数据,需要使用表达式${}填写key去获取Value。如果Value中填写正常字符串,则可以注入基本数据类型。

    1
    2
    3
    4
    @Value("lili")
    private String name;
    @Value("23")
    private int age;
  • 小结:多个同一类型的Bean根据类型装配(Autowired),会报错,那么就需要去指定一个bean去注入,这时候可以通过Qualifier注解去指定名字,或者使用直接使用Resource注解去指定name,也可以通过在Bean组件的类上加Primary注解来标识这个类为主要的类。

9.2 注解标记bean

在需要交给ioc管理的类的上面加管理bean的注解

1
2
@Component
public class DependencyA {}

默认的beanName是该类的首字母小写后的类名,在注解中可以输出值,输入的值就是beanName

1
2
@Component("A")
public class DependencyA {}

9.3 注解注入

注入的时候,是通过暴力反射,将属性直接赋值,并没有使用set方法,所以不会调用set方法

如果需要强行使用set方法,可以将注解放在set方法上

1
2
3
4
5
// 将注解放在set方法上,使用set注入
@Resource(name = "tigaCartoonDao")
public void setCartoonDao(TigaCartoonDao cartoonDao) {
this.cartoonDao = cartoonDao;
}

注入引用属性

1
2
3
4
// 先通过type注入,如果有多个bean,通过name指定对应的bean
@Autowired
@Qualifier("tigaCartoonDao")
private TigaCartoonDao cartoonDao;
1
2
3
4
// 和上面的一样,但是需要导入额外的包
@Inject
@Named("tigaCartoonDao")
private TigaCartoonDao cartoonDao;
1
2
3
4
5
6
7
8
9
10
11
12
// 先通过类型注入,然后通过name注入,相当于上面俩个注解的结合,比较强大
// 这个是java的注解
@Resource(name = "tigaCartoonDao")
private TigaCartoonDao cartoonDao;

// 该注解也可以不给name值,直接通过类型注入
@Resource
private TigaCartoonDao cartoonDao;

// 通过属性的名字也可以指定对应的类型
@Resource
private CartoonDao gardenBabyCartoonDao;
1
2
3
// 如果设计的只有一个实现类,就可以通过一个自动注入的注解进行注入
@Autowired
private TigaCartoonDao cartoonDao;

9.4 上下文创建

和配置文件搭配使用的时候,还是使用的ClassPathXmlApplicationContext(),然后在构造器传入配置文件

需要注意的是,该方式,需要在配置文件中开启组件扫描

1
2
3
4
5
6
7
public class SpringAnnotationTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
// 关闭容器
((ClassPathXmlApplicationContext)context).registerShutdownHook();
}
}

使用注解的上下文,AnnotationConfigApplicationContext(),然后在构造器中传入需要扫描的包

该方式会去什么指定的包,不再需要配置文件

1
2
3
4
5
6
7
8
9
public class SpringAnnotationTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("com.moon.pojo");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}

和java配置文件搭配使用,还是使用AnnotationConfigApplicationContext(),但是需要传入java配置文件类

在java配置文件中需要通过注解去开启扫描

10 基于JavaConfig开发

通过JavaConfig进行管理bean,需要和注解搭配使用

10.1 核心注解

  • @Configuration : 类级别注解,被它所修饰的类就代表一个配置文件,相当于配置文件中的beans

  • @Bean 方法级别注解,修饰配置类中的每一个方法,代表配置文件中的每一个bean

    方法名代表id,返回值代表bean的类型,传入的参数可以传入其他bean,和注解注入一样,先通过类型,再通过name

  • @ComponentScan类级别注解,再配置类中添加该注解,可以对指定的类进行扫描,可以扫描出全部的组件,该注解后面加s后的注解可以传入多个扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
@ComponentScan(basePackages = "com.moon.service")
public class IocConfig {

@Bean
public Woman lili(){
Woman woman = new Woman();
woman.setName("莉莉");
woman.setAge(18);
woman.setOutLook("面容较好的");
return woman;
}

@Bean
@Scope("prototype")
public Man jackMa(Woman lili){
Man man = new Man();
man.setName("杰克马");
man.setFund("数百亿");
man.setWoman(lili);
return man;
}
}

10.2 上下文创建

上下文使用的是AnnotationConfigApplicationContext,这里可以在构造器中传入配置文件的类

1
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);
1
2
3
4
5
6
7
8
9
public class SpringAnnotationTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}