摘要:本文学习了Spring配置对象的三种方式。
环境
Windows 10 企业版 LTSC 21H2
Java 1.8
Tomcat 8.5.50
Maven 3.6.3
Spring 5.2.25.RELEASE
1 XML配置
XML配置是Spring框架最早的配置方式,通过XML文件来定义对象和它们之间的依赖关系。
1.1 基本配置
1.1.1 创建对象
使用bean标签创建对象。
常用属性:
| 属性名 |
作用 |
取值 |
| id |
指定对象的唯一标识 |
唯一标识 |
| class |
指定对象的全类名 |
全类名 |
示例:
xml1 2
| <bean id="user" class="com.example.bean.User"/>
|
1.1.2 设置属性
1.1.2.1 通过Set方法设置属性
使用property标签设置属性。
常用属性:
| 属性名 |
作用 |
取值 |
| name |
指定属性名 |
属性名 |
| value |
指定属性值 |
属性值 |
| ref |
指定引用其他对象的ID |
对象的ID |
注意:
- 需要属性有Set方法,并且方法名按照驼峰命名。
- 必须有无参构造器,默认的无参构造器可以省略。
- 如果属性是基本类型,使用
value属性设置值;如果属性是引用类型,使用ref属性引用其他对象。
示例:
xml1 2 3 4 5 6 7 8 9 10 11 12 13
| <bean id="address" class="com.example.bean.Address"> <property name="province" value="北京市"/> <property name="detail" value="北京市海淀区"/> </bean>
<bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="address" ref="address"/> </bean>
|
1.1.2.2 通过构造器设置属性
使用constructor-arg标签设置属性,需要属性有对应的构造器。
常用属性:
| 属性名 |
作用 |
取值 |
| name |
指定属性名 |
属性名 |
| value |
指定属性值 |
属性值 |
| ref |
指定引用其他对象的ID |
对象的ID |
示例:
xml1 2 3 4 5 6 7 8 9 10 11 12 13
| <bean id="address" class="com.example.bean.Address"> <constructor-arg value="北京市"/> <constructor-arg value="北京市海淀区"/> </bean>
<bean id="user" class="com.example.bean.User"> <constructor-arg value="1"/> <constructor-arg value="张三"/> <constructor-arg value="18"/> <constructor-arg ref="address"/> </bean>
|
1.2 特殊属性
1.2.1 特殊符号
使用value标签设置特殊符号,特殊符号需要使用CDATA包裹,示例:
xml1 2 3 4 5 6 7
| <bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name"> <value><![CDATA[张三]]></value> </property> </bean>
|
1.2.2 级联属性
使用bean标签设置级联属性,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12
| <bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="address"> <bean class="com.example.bean.Address"> <property name="province" value="北京市"/> <property name="detail" value="北京市海淀区"/> </bean> </property> </bean>
|
1.2.3 对象属性
使用bean标签设置对象属性,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12
| <bean id="address" class="com.example.bean.Address"> <constructor-arg value="北京市"/> <constructor-arg value="北京市海淀区"/> </bean>
<bean id="user" class="com.example.bean.User" autowire="byName"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> </bean>
|
使用autowire属性自动装配:
- byName:根据属性名自动装配,如果匹配多个则报错,如果没有匹配则设置为null值。
- byType:根据属性类型自动装配,如果匹配多个则报错,如果没有匹配则设置为null值。
- constructor:根据构造器参数自动装配,不常用。
1.2.4 数组属性
使用array标签设置数组属性。
1.2.4.1 基本类型
使用value标签设置基本类型数据,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12
| <bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="hobbies"> <array> <value>篮球</value> <value>足球</value> </array> </property> </bean>
|
1.2.4.2 引用类型
使用bean标签设置引用类型数据,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="addresses"> <array> <bean class="com.example.bean.Address"> <property name="province" value="北京市"/> <property name="detail" value="北京市海淀区"/> </bean> <bean class="com.example.bean.Address"> <property name="province" value="上海市"/> <property name="detail" value="上海市静安区"/> </bean> </array> </property> </bean>
|
使用ref标签引用其他对象,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <bean id="address1" class="com.example.bean.Address"> <property name="province" value="北京市"/> <property name="detail" value="北京市海淀区"/> </bean> <bean id="address2" class="com.example.bean.Address"> <property name="province" value="上海市"/> <property name="detail" value="上海市静安区"/> </bean>
<bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="addresses"> <array> <ref bean="address1"/> <ref bean="address2"/> </array> </property> </bean>
|
1.2.5 集合属性
使用list标签设置List集合属性,支持基本类型和引用类型,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12
| <bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="pets"> <list> <value>小猫</value> <value>小狗</value> </list> </property> </bean>
|
使用set标签设置Set集合属性,支持基本类型和引用类型,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12
| <bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="pets"> <list> <value>小猫</value> <value>小狗</value> </list> </property> </bean>
|
使用map标签设置Map集合属性,支持基本类型和引用类型,示例:
xml1 2 3 4 5 6 7 8 9 10 11 12
| <bean id="user" class="com.example.bean.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="18"/> <property name="pets"> <map> <entry key="cat" value="小猫"/> <entry key="dog" value="小狗"/> </map> </property> </bean>
|
1.3 工厂对象
1.3.1 静态工厂方法
创建静态工厂实体类,工厂方法需要是静态方法:
java1 2 3 4 5
| public class UserFactory { public static User getUser() { return new User(1, "张三", 18); } }
|
使用factory-method属性指定工厂方法,示例:
xml1 2
| <bean id="user" class="com.example.factory.UserFactory" factory-method="getUser"/>
|
1.3.2 实例工厂方法
创建实例工厂实体类,工厂方法不能是静态方法:
java1 2 3 4 5
| public class UserFactory { public User getUser() { return new User(1, "张三", 18); } }
|
使用factory-bean属性指定实例工厂,使用factory-method属性指定工厂方法,示例:
xml1 2 3 4
| <bean id="userFactory" class="com.example.factory.UserFactory"/>
<bean id="user" factory-bean="userFactory" factory-method="getUser"/>
|
1.3.3 使用工厂接口
创建FactoryBean实体类,实现FactoryBean接口:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class UserFactoryBean implements FactoryBean<User> { @Override public User getObject() throws Exception { return new User(1, "张三", 18); } @Override public Class<?> getObjectType() { return User.class; } @Override public boolean isSingleton() { return FactoryBean.super.isSingleton(); } }
|
示例:
xml1 2
| <bean id="user" class="com.example.factory.UserFactoryBean"/>
|
1.4 设置作用域
使用scope属性设置作用域,常用取值:
- singleton:单例模式,容器初始化时创建对象,整个容器中只有一个实例(默认)
- prototype:原型模式,每次获取对象时都会创建一个新的实例
- request:每次HTTP请求都会创建一个新的实例,仅适用于Web应用
- session:每个HTTP会话创建一个新的实例,仅适用于Web应用
示例:
xml1 2
| <bean id="user" class="com.example.bean.User" scope="prototype"/>
|
1.5 管理生命周期
对象的生命周期:
- 执行构造方法创建对象。
- 执行设置方法设置对象属性。
- 执行初始化方法。
- 执行使用方法。
- 执行销毁方法,在容器关闭时自动调用。
1.5.1 使用配置文件
修改实体类:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class User { private Integer id; public User() { System.out.println("执行构造方法"); } public Integer getId() { System.out.println("执行Get使用方法"); return id; } public void setId(Integer id) { System.out.println("执行Set设置方法"); this.id = id; } public void initMethod() { System.out.println("执行自定义初始化方法"); } public void destroyMethod() { System.out.println("执行自定义销毁方法"); } }
|
修改配置文件:
xml1 2 3 4
| <bean id="user" class="com.example.bean.User" init-method="initMethod" destroy-method="destroyMethod"> <property name="id" value="1"/> </bean>
|
修改启动类:
java1 2 3 4 5 6 7 8 9 10 11 12
| public class DemoApplication { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); User user = context.getBean(User.class); System.out.println(user.getId()); context.close(); } }
|
结果:
log1 2 3 4 5 6
| 执行构造方法 执行Set设置方法 执行自定义初始化方法 执行Get使用方法 1 执行自定义销毁方法
|
1.5.2 实现接口
可以通过实现接口管理生命周期:
- 实现InitializingBean接口可以在属性设置完成后执行初始化操作。
- 实现DisposableBean接口可以在容器关闭前执行销毁操作。
示例:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class User implements InitializingBean, DisposableBean { private Integer id; public User() { System.out.println("执行构造方法"); } public Integer getId() { System.out.println("执行Get使用方法"); return id; } public void setId(Integer id) { System.out.println("执行Set设置方法"); this.id = id; } public void initMethod() { System.out.println("执行自定义初始化方法"); } public void destroyMethod() { System.out.println("执行自定义销毁方法"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("执行InitializingBean的afterPropertiesSet方法"); } @Override public void destroy() throws Exception { System.out.println("执行DisposableBean的destroy方法"); } }
|
结果:
log1 2 3 4 5 6 7 8
| 执行构造方法 执行Set设置方法 执行InitializingBean的afterPropertiesSet方法 执行自定义初始化方法 执行Get使用方法 1 执行DisposableBean的destroy方法 执行自定义销毁方法
|
1.5.3 后置处理器
后置处理器允许在对象的生命周期的不同阶段进行干预,主要有两种类型:
- BeanPostProcessor:在对象初始化前后进行处理,可以修改对象的实例。
- BeanFactoryPostProcessor:在BeanFactory初始化后,并且在对象实例化之前进行处理,可以修改对象的定义。
1.5.3.1 对象后置处理器
实现BeanPostProcessor接口需要重写两个方法:
- postProcessBeforeInitialization:在对象初始化前调用,可以修改对象属性。
- postProcessAfterInitialization:在对象初始化后调用,可以返回代理对象。
示例:
java1 2 3 4 5 6 7 8 9 10 11 12
| public class DemoPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("执行BeanPostProcessor的postProcessBeforeInitialization方法"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("执行BeanPostProcessor的postProcessAfterInitialization方法"); return bean; } }
|
配置:
xml1 2 3 4 5 6 7
| <bean id="user" class="com.example.bean.User" init-method="initMethod" destroy-method="destroyMethod"> <property name="id" value="1"/> </bean>
<bean id="demoPostProcessor" class="com.example.processor.DemoPostProcessor"/>
|
结果:
log1 2 3 4 5 6 7 8 9 10
| 执行构造方法 执行Set设置方法 执行BeanPostProcessor的postProcessBeforeInitialization方法 执行InitializingBean的afterPropertiesSet方法 执行自定义初始化方法 执行BeanPostProcessor的postProcessAfterInitialization方法 执行Get使用方法 1 执行DisposableBean的destroy方法 执行自定义销毁方法
|
1.5.3.2 对象工厂后置处理器
实现BeanFactoryPostProcessor接口需要重写postProcessBeanFactory()方法,在BeanFactory初始化后调用,可以修改对象定义。
示例:
java1 2 3 4 5 6
| public class DemoFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("执行BeanFactoryPostProcessor的postProcessBeanFactory方法"); } }
|
配置:
xml1 2 3 4 5 6 7 8 9 10
| <bean id="user" class="com.example.bean.User" init-method="initMethod" destroy-method="destroyMethod"> <property name="id" value="1"/> </bean>
<bean id="demoPostProcessor" class="com.example.processor.DemoPostProcessor"/>
<bean id="demoFactoryPostProcessor" class="com.example.processor.DemoFactoryPostProcessor"/>
|
结果:
log1 2 3 4 5 6 7 8 9 10 11
| 执行BeanFactoryPostProcessor的postProcessBeanFactory方法 执行构造方法 执行Set设置方法 执行BeanPostProcessor的postProcessBeforeInitialization方法 执行InitializingBean的afterPropertiesSet方法 执行自定义初始化方法 执行BeanPostProcessor的postProcessAfterInitialization方法 执行Get使用方法 1 执行DisposableBean的destroy方法 执行自定义销毁方法
|
2 半注解配置
从Spring的2.5版本开始,引入了基于注解的配置方式,大大简化了配置工作:
- 在
spring.xml配置文件中使用context:component-scan标签启用对象扫描,需要在XML文件中添加context命名空间。
- 使用
@Component注解自动创建对象。
2.1 基本配置
创建实体类:
java1 2 3 4 5
| @Component public class User { private Integer id; }
|
创建配置文件:
spring.xml1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.example"/> </beans>
|
创建启动类:
java1 2 3 4 5 6 7 8 9 10 11 12
| public class DemoApplication { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); User user = context.getBean(User.class); System.out.println(user); context.close(); } }
|
2.2 自动注入
在spring.xml配置文件中使用context:annotation-config标签启用自动注入,自动对容器中的对象注入依赖。
2.3 配置扫描
在spring.xml配置文件中使用context:component-scan标签启用对象扫描,将标注了特定注解的类自动注册到容器中,并且自动对容器中的对象注入依赖。
使用context:component-scan标签可以覆盖context:annotation-config标签的自动注入功能。
常用属性:
| 属性名 |
作用 |
取值 |
| base-package |
指定需要扫描的包路径 |
包路径,多个使用逗号分隔 |
| resource-pattern |
指定扫描的资源模式,按类匹配 |
表达式 |
示例:
xml1 2
| <context:component-scan base-package="com.example" resource-pattern="**/*Controller.class"/>
|
说明:
2.4 常用注解
2.4.1 标识注解
使用注解标识对象可以简化XML配置,支持通过value属性指定对象名称:
- 使用
@Component注解标识通用的对象。
- 使用
@Repository注解标识数据访问层的对象。
- 使用
@Service注解标识服务层的对象。
- 使用
@Controller注解标识接入层的对象。
示例:
java1 2 3 4 5
| @Component public class User { private Integer id; }
|
2.4.2 属性注解
使用@Value注解可以注入基本类型的属性值,支持字段注入、方法注入、构造器注入。
示例:
java1 2 3 4 5 6
| @Component public class User { @Value("1") private Integer id; }
|
2.4.3 注入注解
2.4.3.1 @Autowired
使用@Autowired注解可以根据类型注入依赖:
- 支持字段注入、方法注入、构造器注入。
- 如果有且仅有一个类型相同的对象,则注入该对象。
- 如果有多个类型相同的对象,则会抛出异常。需要使用
@Qualifier注解指定具体的对象。
- 如果找不到类型相同的对象,则会抛出异常。在设置required属性为false后,找不到会设置为null值,不会抛出异常。
示例:
java1 2 3 4 5 6 7 8 9
| @Component public class User { @Value("1") private Integer id; @Autowired @Qualifier("address") private Address address; }
|
2.4.3.2 @Inject
使用@Inject注解可以根据名称或类型注入依赖,这是由JDK提供的注解,属于JSR-330规范:
- 支持字段注入、方法注入、构造器注入。
- 如果有且仅有一个类型相同的对象,则注入该对象。
- 如果有多个类型相同的对象,则会抛出异常。需要使用
@Named注解指定具体的对象。
- 如果找不到类型相同的对象,则会抛出异常。
添加依赖:
pom.xml1 2 3 4 5 6
| <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
|
示例:
java1 2 3 4 5 6 7 8 9
| @Component public class User { @Value("1") private Integer id; @Inject @Named("address") private Address address; }
|
2.4.3.3 @Resource
使用@Resource注解可以根据名称或类型注入依赖,这是由JDK提供的注解,属于JSR-250规范:
- 支持字段注入、方法注入,不支持构造器注入。
- 如果有且仅有一个名称相同的对象,则自动装配该对象。
- 如果有多个名称相同的对象,则会抛出异常。
- 如果找不到名称相同的对象,则会匹配类型相同的对象。
- 如果有且仅有一个类型相同的对象,则自动装配该对象。
- 如果有多个类型相同的对象,则会抛出异常。
- 如果找不到类型相同的对象,则会抛出异常。
示例:
java1 2 3 4 5 6 7 8
| @Component public class User { @Value("1") private Integer id; @Resource private Address address; }
|
2.5 设置作用域
使用@Scope注解可以在标识对象时设置作用域。
示例:
java1 2 3 4 5 6 7
| @Component @Scope("prototype") public class User { @Value("1") private Integer id; }
|
2.6 管理生命周期
2.6.1 使用注解
可以通过使用JDK自带的注解管理生命周期:
- 使用
@PostConstruct注解可以在属性设置完成后执行初始化操作。
- 使用
@PreDestroy注解可以在容器关闭前执行销毁操作。
修改实体类:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Component public class User { private Integer id; public User() { System.out.println("执行构造方法"); } public Integer getId() { System.out.println("执行Get使用方法"); return id; } @Value("1") public void setId(Integer id) { System.out.println("执行Set设置方法"); this.id = id; } @PostConstruct public void initMethod() { System.out.println("执行自定义初始化方法"); } @PreDestroy public void destroyMethod() { System.out.println("执行自定义销毁方法"); } }
|
修改启动类:
java1 2 3 4 5 6 7 8 9 10 11 12
| public class DemoApplication { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); User user = context.getBean(User.class); System.out.println(user.getId()); context.close(); } }
|
结果:
log1 2 3 4 5 6
| 执行构造方法 执行Set设置方法 执行自定义初始化方法 执行Get使用方法 1 执行自定义销毁方法
|
2.6.2 实现接口
可以通过实现接口管理生命周期:
- 实现InitializingBean接口可以在属性设置完成后执行初始化操作。
- 实现DisposableBean接口可以在容器关闭前执行销毁操作。
示例:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Component public class User implements InitializingBean, DisposableBean { private Integer id; public User() { System.out.println("执行构造方法"); } public Integer getId() { System.out.println("执行Get使用方法"); return id; } @Value("1") public void setId(Integer id) { System.out.println("执行Set设置方法"); this.id = id; } @PostConstruct public void initMethod() { System.out.println("执行自定义初始化方法"); } @PreDestroy public void destroyMethod() { System.out.println("执行自定义销毁方法"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("执行InitializingBean的afterPropertiesSet方法"); } @Override public void destroy() throws Exception { System.out.println("执行DisposableBean的destroy方法"); } }
|
结果:
log1 2 3 4 5 6 7 8
| 执行构造方法 执行Set设置方法 执行自定义初始化方法 执行InitializingBean的afterPropertiesSet方法 执行Get使用方法 1 执行自定义销毁方法 执行DisposableBean的destroy方法
|
2.6.3 后置处理器
后置处理器允许在对象的生命周期的不同阶段进行干预,主要有两种类型:
- BeanPostProcessor:在对象初始化前后进行处理,可以修改对象的实例。
- BeanFactoryPostProcessor:在BeanFactory初始化后,并且在对象实例化之前进行处理,可以修改对象的定义。
2.6.3.1 对象后置处理器
实现BeanPostProcessor接口需要重写两个方法:
- postProcessBeforeInitialization:在对象初始化前调用,可以修改对象属性。
- postProcessAfterInitialization:在对象初始化后调用,可以返回代理对象。
示例:
java1 2 3 4 5 6 7 8 9 10 11 12 13
| @Component public class DemoPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("执行BeanPostProcessor的postProcessBeforeInitialization方法"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("执行BeanPostProcessor的postProcessAfterInitialization方法"); return bean; } }
|
结果:
log1 2 3 4 5 6 7 8 9 10
| 执行构造方法 执行Set设置方法 执行BeanPostProcessor的postProcessBeforeInitialization方法 执行自定义初始化方法 执行InitializingBean的afterPropertiesSet方法 执行BeanPostProcessor的postProcessAfterInitialization方法 执行Get使用方法 1 执行自定义销毁方法 执行DisposableBean的destroy方法
|
2.6.3.2 对象工厂后置处理器
实现BeanFactoryPostProcessor接口需要重写postProcessBeanFactory()方法,在BeanFactory初始化后调用,可以修改对象定义。
示例:
java1 2 3 4 5 6 7
| @Component public class DemoFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("执行BeanFactoryPostProcessor的postProcessBeanFactory方法"); } }
|
结果:
log1 2 3 4 5 6 7 8 9 10 11
| 执行BeanFactoryPostProcessor的postProcessBeanFactory方法 执行构造方法 执行Set设置方法 执行BeanPostProcessor的postProcessBeforeInitialization方法 执行自定义初始化方法 执行InitializingBean的afterPropertiesSet方法 执行BeanPostProcessor的postProcessAfterInitialization方法 执行Get使用方法 1 执行自定义销毁方法 执行DisposableBean的destroy方法
|
3 全注解配置
从Spring的3.0版本开始,引入了全注解配置方式:
- 使用
@Configuration注解替代spring.xml配置文件。
- 使用
@ComponentScan注解替代context:component-scan标签启用对象扫描。
- 使用
@Bean注解替代bean标签创建对象实例。
需要将容器改为AnnotationConfigApplicationContext类型,并且传入配置类,使用注解的方式获取配置。
3.1 基本配置
创建实体类:
java1 2 3 4 5
| @Component public class User { private Integer id; }
|
创建配置类:
java1 2 3 4
| @Configuration @ComponentScan("com.example") public class DemoConfig { }
|
创建启动类:
java1 2 3 4 5 6 7 8 9 10 11 12
| public class DemoApplication { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class); User user = context.getBean(User.class); System.out.println(user); context.close(); } }
|
3.2 常用注解
3.2.1 配置注解
使用@Configuration注解可以标记配置类,本质上是@Component注解的特例,所以配置类会被注册为对象。
常用属性:
| 属性名 |
作用 |
取值 |
| value |
指定对象名称 |
对象名称,默认使用类名 |
| proxyBeanMethods |
设置通过@Bean注解创建的对象是否使用CGLIB代理,使用代理创建单例对象 |
默认为true表示使用代理,设置为false表示不使用代理td>
|
示例:
java1 2 3
| @Configuration(value = "demoConfig", proxyBeanMethods = false) public class DemoConfig { }
|
3.2.2 扫描注解
使用@ComponentScan注解可以启用对象扫描,代替在spring.xml配置文件中使用context:component-scan标签。
常用属性:
| 属性名 |
作用 |
取值 |
| value或basePackages |
指定要扫描的包路径 |
包路径,多个使用逗号分隔 |
| basePackageClasses |
指定要扫描的类路径 |
类路径,多个使用逗号分隔 |
| includeFilters |
指定包含过滤器,满足这些过滤器的类会被注册为对象 |
表达式 |
| excludeFilters |
指定排除过滤器,满足这些过滤器的类不会被注册为对象 |
表达式 |
| useDefaultFilters |
是否使用默认过滤器,默认过滤器会自动注册带有四种标识注解的类 |
默认为true表示使用默认过滤器,设置为false禁用后只注册用户自定义的过滤器 |
过滤器类型:
- Filter.TYPE_ANNOTATION:注解过滤器
- Filter.TYPE_ASSIGNABLE:类型过滤器
- Filter.TYPE_ASPECTJ:AspectJ表达式过滤器
- Filter.TYPE_REGEX:正则表达式过滤器
示例:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration @ComponentScan( basePackages = "com.example", useDefaultFilters = false, includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class), @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class) }, excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*Test") } ) public class DemoConfig { }
|
3.2.3 对象注解
使用@Bean注解可以注册对象,需要在配置类中使用。
使用@Bean注解修饰的方法可以传入参数,支持的参数类型:
- 容器中的对象:支持注入容器中的其他对象,包括使用
@Component注解或者@Bean注解创建的对象。
- ApplicationContext:支持注入应用上下文对象,可以获取容器中的其他对象。
- ResourceLoader:支持注入资源加载器对象,可以加载资源文件。
@Value:支持注入配置属性值,可以获取配置文件中的配置。
- Environment:支持注入环境对象,可以获取配置文件中的配置。
常用属性:
| 属性名 |
作用 |
取值 |
| value或name |
指定对象名称 |
对象名称,默认使用方法名 |
| initMethod |
指定初始化方法 |
方法名 |
| destroyMethod |
指定销毁方法 |
方法名 |
示例:
java1 2 3 4 5 6 7
| @Configuration public class DemoConfig { @Bean("user") public User user() { return new User(); } }
|
3.2.4 依赖注解
使用@DependsOn注解可以指定依赖的对象,用于显示声明依赖关系,可以在标识注解和对象注解中使用。
示例:
java1 2 3 4 5 6
| @Component @DependsOn("address") public class User { private Address address; }
|
3.2.5 导入注解
使用@Import注解可以导入其他类,多个类之间使用逗号分隔。
支持:
- 导入普通类:普通类会被注册为对象。
- 导入配置类:可以使用配置类中的对象,还可以通过接口灵活选择。
示例:
java1 2 3 4
| @Configuration @Import(User.class) public class DemoConfig { }
|
3.2.6 资源注解
使用@PropertySource注解可以获取配置文件,可以通过@Value注解或者注入Environment环境变量读取。
通过@Value注解读取:
java1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration @PropertySource("classpath:demo.properties") public class DemoConfig { @Value("${user.id}") private Integer id; @Bean public User user() { User user = new User(); user.setId(id); return user; } }
|
通过注入Environment环境变量读取:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Configuration @PropertySource("classpath:demo.properties") public class DemoConfig { private Environment env; @Autowired public void setEnv(Environment env) { this.env = env; } @Bean public User user() { User user = new User(); user.setId(Integer.parseInt(env.getProperty("user.id"))); return user; } }
|
3.3 管理生命周期
3.3.1 使用属性
使用@Bean注解可以管理生命周期:
- 通过
initMethod属性指定初始化方法。
- 通过
destroyMethod属性指定销毁方法。
也可以通过使用JDK自带的注解管理生命周期:
- 使用
@PostConstruct注解可以在属性设置完成后执行初始化操作。
- 使用
@PreDestroy注解可以在容器关闭前执行销毁操作。
修改实体类:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class User { private Integer id; public User() { System.out.println("执行构造方法"); } public Integer getId() { System.out.println("执行Get使用方法"); return id; } @Value("1") public void setId(Integer id) { System.out.println("执行Set设置方法"); this.id = id; } public void initMethodAttr() { System.out.println("执行属性自定义初始化方法"); } public void destroyMethodAttr() { System.out.println("执行属性自定义销毁方法"); } @PostConstruct public void initMethodFunc() { System.out.println("执行注解自定义初始化方法"); } @PreDestroy public void destroyMethodFunc() { System.out.println("执行注解自定义销毁方法"); } }
|
修改配置类:
java1 2 3 4 5 6 7
| @Configuration public class DemoConfig { @Bean(name = "user", initMethod = "initMethodAttr", destroyMethod = "destroyMethodAttr") public User user() { return new User(); } }
|
修改启动类:
java1 2 3 4 5 6 7 8 9 10 11 12
| public class DemoApplication { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class); User user = context.getBean(User.class); System.out.println(user.getId()); context.close(); } }
|
结果:
log1 2 3 4 5 6 7 8
| 执行构造方法 执行Set设置方法 执行注解自定义初始化方法 执行属性自定义初始化方法 执行Get使用方法 1 执行注解自定义销毁方法 执行属性自定义销毁方法
|
3.3.2 实现接口
可以通过实现接口管理生命周期:
- 实现InitializingBean接口可以在属性设置完成后执行初始化操作。
- 实现DisposableBean接口可以在容器关闭前执行销毁操作。
示例:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class User implements InitializingBean, DisposableBean { private Integer id; public User() { System.out.println("执行构造方法"); } public Integer getId() { System.out.println("执行Get使用方法"); return id; } @Value("1") public void setId(Integer id) { System.out.println("执行Set设置方法"); this.id = id; } public void initMethodAttr() { System.out.println("执行属性自定义初始化方法"); } public void destroyMethodAttr() { System.out.println("执行属性自定义销毁方法"); } @PostConstruct public void initMethodFunc() { System.out.println("执行注解自定义初始化方法"); } @PreDestroy public void destroyMethodFunc() { System.out.println("执行注解自定义销毁方法"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("执行InitializingBean的afterPropertiesSet方法"); } @Override public void destroy() throws Exception { System.out.println("执行DisposableBean的destroy方法"); } }
|
结果:
log1 2 3 4 5 6 7 8 9 10
| 执行构造方法 执行Set设置方法 执行注解自定义初始化方法 执行InitializingBean的afterPropertiesSet方法 执行属性自定义初始化方法 执行Get使用方法 1 执行注解自定义销毁方法 执行DisposableBean的destroy方法 执行属性自定义销毁方法
|
3.3.3 后置处理器
后置处理器允许在对象的生命周期的不同阶段进行干预,主要有两种类型:
- BeanPostProcessor:在对象初始化前后进行处理,可以修改对象的实例。
- BeanFactoryPostProcessor:在BeanFactory初始化后,并且在对象实例化之前进行处理,可以修改对象的定义。
3.3.3.1 对象后置处理器
实现BeanPostProcessor接口需要重写两个方法:
- postProcessBeforeInitialization:在对象初始化前调用,可以修改对象属性。
- postProcessAfterInitialization:在对象初始化后调用,可以返回代理对象。
示例:
java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Component public class DemoPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof User) { System.out.println("执行BeanPostProcessor的postProcessBeforeInitialization方法"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof User) { System.out.println("执行BeanPostProcessor的postProcessAfterInitialization方法"); } return bean; } }
|
结果:
log1 2 3 4 5 6 7 8 9 10 11 12
| 执行构造方法 执行Set设置方法 执行BeanPostProcessor的postProcessBeforeInitialization方法 执行注解自定义初始化方法 执行InitializingBean的afterPropertiesSet方法 执行属性自定义初始化方法 执行BeanPostProcessor的postProcessAfterInitialization方法 执行Get使用方法 1 执行注解自定义销毁方法 执行DisposableBean的destroy方法 执行属性自定义销毁方法
|
3.3.3.2 对象工厂后置处理器
实现BeanFactoryPostProcessor接口需要重写postProcessBeanFactory()方法,在BeanFactory初始化后调用,可以修改对象定义。
示例:
java1 2 3 4 5 6 7
| @Component public class DemoFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("执行BeanFactoryPostProcessor的postProcessBeanFactory方法"); } }
|
结果:
log1 2 3 4 5 6 7 8 9 10 11 12 13
| 执行BeanFactoryPostProcessor的postProcessBeanFactory方法 执行构造方法 执行Set设置方法 执行BeanPostProcessor的postProcessBeforeInitialization方法 执行注解自定义初始化方法 执行InitializingBean的afterPropertiesSet方法 执行属性自定义初始化方法 执行BeanPostProcessor的postProcessAfterInitialization方法 执行Get使用方法 1 执行注解自定义销毁方法 执行DisposableBean的destroy方法 执行属性自定义销毁方法
|
条