<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
在早期的时候,我们都是使用bean.xml的方式创建一个bean对象
<?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 class="com.dmg.User" id="user">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
</beans>
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/c384fc70d889167d8bf5e00990e8e8d0.png)
但是当我们使用注解的时候可以这样使用,注入到ioc容器中
@Configuration表示这是一个配置类,对应bean.xml
@Bean 表示 <bean class="com.dmg.User" id="user">
这里的user2就是bean id
@Configuration
public class TestConfig {
@Bean
public User user2(){
User user=new User();
user.setAge(66);
user.setName("李四");
return user;
}
}
AnnotationConfigApplicationContext 表示注解配置应用上下文
使用了@Configuration这个注解,我们都可以访问到
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(TestConfig.class);
User user = (User) applicationContext.getBean("user2");
System.out.println(user);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/af00589545ad061e683318ef314b749c.png)
我们也可以在@Bean(这里该改名字)
![](https://i-blog.csdnimg.cn/blog_migrate/c876860929927ade221aabf70bb7cfa0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/07685172020a9d5a67333a622b0d5c9f.png)
我们可以通过 applicationContext.getBeanDefinitionNames()来获取容器中的bean定义名称信息
![](https://i-blog.csdnimg.cn/blog_migrate/718cdde2639e22e09f03253f9ba93dc0.png)
AnnotationConfigApplicationContext能返回ApplicationContext是因为
最终继承的ApplicationContext,所以可以返回ApplicationContext
![](https://i-blog.csdnimg.cn/blog_migrate/dcb9f169ff896290498ed90ada208383.png)
我们的容器中的user对象默认是单实例的,来看下场景
可以看到2次获取的时候都是true,这就是单实例
![](https://i-blog.csdnimg.cn/blog_migrate/e798df9bc1c9e45f958908115e19aa86.png)
我们把applicationContext.getBean注释掉
在箭头位置加入一行数据
![](https://i-blog.csdnimg.cn/blog_migrate/a4c81b58026a176b6085e7f211d0c863.png)
可以看到在单实例作用域下,先给容器加载数据,所以在容器中获取bean的时候直接从容器拿
![](https://i-blog.csdnimg.cn/blog_migrate/52eaa118410759a246650ef1266df115.png)
我们在看下多实例,使用@Scope("prototype")
![](https://i-blog.csdnimg.cn/blog_migrate/678040f42ad7995d66b1dbe8bab63796.png)
我们启动的时候,并没有看到打印的那一行内容,只有加载完毕的信息
![](https://i-blog.csdnimg.cn/blog_migrate/d755fcb3cf95b5d5b34f807ced2aa2ad.png)
我们把获取bean的注释放开
可以看到,获取一次bean,打印一次,结果为false,这就是多实例
![](https://i-blog.csdnimg.cn/blog_migrate/800e31ceaa7f1fa523a99f3f4a481751.png)
我们可以在单实例环境下设置@Lazy 延时加载
等获取bean的时候,才创建对象
![](https://i-blog.csdnimg.cn/blog_migrate/c5ecf5bc9d0490275b388cf7b8e1fc15.png)
可以看到,获取bean也只打印一次,返回true
![](https://i-blog.csdnimg.cn/blog_migrate/ce986dc64e2d36cec52435bad4205f66.png)
我们来看下@Bean手动指定初始化和销毁的方法
手动指定bean的生命周期
public class Sp {
public Sp(){
System.out.println("对象创建了");
}
public void init(){
System.out.println("对象初始化了");
}
public void destory(){
System.out.println("对象销毁了");
}
}
在initMethod写上初始化的方法
在destroyMethod写上销毁的方法
@Configuration
public class TestConfig {
@Bean(initMethod = "init",destroyMethod = "destory")
public Sp sp(){
return new Sp();
}
}
单实例环境下,容器启动的时候会创建对象,
容器销毁的时候,会销毁对象
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(TestConfig.class);
System.out.println("容器创建完成了");
applicationContext.close();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/079130fad6a4d0cdab8ec3ae2bdc0583.png)
我们在看下多实例的场景
设置@Scope("prototype")
可以看到并没去创建对象,只有在获取bean的时候,才创建对象
销毁的时候,容器也不会去销毁这个对象
![](https://i-blog.csdnimg.cn/blog_migrate/0ac964a2d491cf07fa53bcada1f9a1b6.png)
我们还可以通过实现InitializingBean, DisposableBean
来写属性赋值之后的方法,销毁的方法
public class Sp implements InitializingBean, DisposableBean {
private String name;
public Sp(){
System.out.println("对象创建了");
}
public void setName(String name) {
System.out.println("属性赋值");
this.name = name;
}
public void afterPropertiesSet() throws Exception {
System.out.println("属性赋值之后执行");
}
public void destroy() throws Exception {
System.out.println("对象销毁了");
}
}
@Configuration
public class TestConfig {
@Bean
public Sp sp(){
Sp sp=new Sp();
sp.setName("aaa");
return sp;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8794e705ec7b2f3133819dc68690071e.png)
我们还可以使用@PostConstruct 来设置对象创建完成并且属性赋值之后,进行初始化
使用@PreDestroy 在容器销毁bean之前执行此方法
public class Sp {
private String name;
public Sp(){
System.out.println("对象创建了");
}
public void setName(String name) {
System.out.println("属性赋值");
this.name = name;
}
@PostConstruct
public void aa(){
System.out.println("对象创建之后,并且属性赋值之后执行");
}
@PreDestroy
public void bb(){
System.out.println("容器销毁对象之前执行");
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/3c5c64b4f722eba0d7a70261dedc8dc3.png)
我们还可以实现BeanPostProcessor 后置bean处理器,来进行初始化之前的操作,初始化之后的操作
public class Linux implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行:"+beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行:"+beanName);
return bean;
}
}
@Configuration
public class TestConfig {
@Bean
public Sp sp(){
Sp sp=new Sp();
sp.setName("aaa");
return sp;
}
@Bean
public Linux linux(){
return new Linux();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/96a2370ec1b7cd35570672963a65d5f7.png)
我们来看下源码分析,在postProcessBeforeInitialization方法打个断点
执行之后会先进入applyBeanPostProcessorsBeforeInitialization 执行bean后置处理器之前初始化方法
在这个result就拿到了bean的信息
![](https://i-blog.csdnimg.cn/blog_migrate/302daff5b0ffd6f7834c54ef0430b9a0.png)
然后再进入applyBeanPostProcessorsAfterInitialization
执行bean后置处理器之后初始化方法
![](https://i-blog.csdnimg.cn/blog_migrate/b7fbe4cf9b89a8c351b15b12fc3456a3.png)
等方法执行到postProcessAfterInitialization这里的时候,就会进入
我们linux类的postProcessAfterInitialization方法
![](https://i-blog.csdnimg.cn/blog_migrate/a7ec55cf208d2c147a889ca784b18e7d.png)
初始化之前的操作和初始化之后的操作,都是在initializeBean这个方法里面去执行的
![](https://i-blog.csdnimg.cn/blog_migrate/056ef5e32a751b5fc84f01c4c5e3bad8.png)
我们也可以实现ApplicationContextAware接口,在创建完对象,并且属性赋值之后,
使用应用程序上下文
public class Sp implements ApplicationContextAware {
private ApplicationContext applicationContext;
private String name;
public Sp(){
System.out.println("对象创建了");
}
public void setName(String name) {
System.out.println("属性赋值");
this.name = name;
}
@PostConstruct
public void aa(){
System.out.println("对象创建之后,并且属性赋值之后执行");
}
@PreDestroy
public void bb(){
System.out.println("容器销毁对象之前执行");
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
System.out.println("在容器中使用应用上下文");
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/ea83221eef8b8c4dbc7bee4347512575.png)
进入源码ApplicationContextAwareProcessor类
可以看到他也是实现的BeanPostProcessor
我们进入invokeAwareInterfaces方法
![](https://i-blog.csdnimg.cn/blog_migrate/d77e35a6a5a611d9dcd73040157febe0.png)
可以看到当这个bean是实现了ApplicationContextAware
那么会进入对应的类去执行setApplicationContext方法
![](https://i-blog.csdnimg.cn/blog_migrate/af03d46476ef47c09871ec8a7f923ad1.png)
这样就能拿到应用程序上下文了,然后在其他方法就可以使用这个了
![](https://i-blog.csdnimg.cn/blog_migrate/c4da2e8ea0062b03aaca380b6add49da.png)
我们使用@PostConstruct和@PreDestroy这2个注解能执行
就是因为他的BeanPostProcessor类的postProcessBeforeInitialization方法
我们进入源码InitDestroyAnnotationBeanPostProcessor类
可以看到,在这里就能拿到初始化和销毁的方法,然后执行之后就进入了
对应的注解的方法
![](https://i-blog.csdnimg.cn/blog_migrate/7c156368c38af507dae2c6f7d62fd444.png)
![](https://i-blog.csdnimg.cn/blog_migrate/34c5c0bd8075797f6244b2db57118478.png)