使ssm的的时候。首先就会找到spring ,为什么?
应为我们需要将对象交给srping来统一管理,
我们先来复习一下,spring的两大特性
ioc 我们同过spring来帮助我们创建类,帮助我们类之间的解耦
aop 可以在不改变类的源码情况下,添加一些增强的方法,可以是前置,后置 ,异常等等
我们想要用框架,实现越来越多的功能的时候,往往要填加很多很多的bean组件,在使用的时候就可以直接去使用ioc容器中的类,
创建类也有区分不同
这些都需要有对应的后置处理器,接下来我们就来看看spring给我们提供了那些灵活的处理器,只要是注入到容器中的bean在即将初始化的时候,都会执行后置处理器,完成之后才放入spring的池子中。
BeanPostProcessor
: bean的后置处理器作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。接口的源码如下
源码中有两个方法:
postProcessBeforeInitialization
:实例化,依赖注入完毕,再调用显示初始化之前完成游戏额定制初始化的任务
postProcessAfterInitialization
:实例化,依赖注入,初始化后执行
这里我们写个小demo来体验一下
新建一个类,叫myBeanPostProcessor
,我们实现这个后置处理器的接口
参数解释 :
参数1 bean :就是我们注入到ioc的对象
参数2 beanName : 就是我们注入到ioc的对象名字
public class MyBeanPostProcessor 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;
}
}
简单实例,实行之后,可以看我们注入对象的初始化前和初始化后的输出信息
这个bean工厂处理器,是在所有bean的创造之前对bean的一些修改,我们可以在没有构造对象之前,对bean做什么,
postProcessBeanFactory
方法 : 参数有bean工厂的对象,可以查看到一些信息
他就是返回一个在bena创建之前的创建工厂对象,我们可以查看工厂中要创建的bean信息
为了处理我们在放容器到spring的时候的一些配置,比如是否单例,初始化方法,销毁方法,等等信息的后置处理器
方法
postProcessBeanDefinitionRegistry
bean对象的配置信息注册
postProcessBeanFactory
之后进到bean的工厂
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry)
throws BeansException {
System.out.println("postProcessBeanDefinitionRegistry:" + beanDefinitionRegistry);
}
public void postProcessBeanFactory(
ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("ConfigurableListableBeanFactory:" + configurableListableBeanFactory);
}
Bean组件的各个生命周期
全新配置文件 : beanFactoryProcessor.xml
,就放两个没有任何配置的bean对象
<bean id="mypostProcessBeanFactory" class="com.hyc.Processor.MypostProcessBeanFactory"/>
<bean id="demobean" class="com.hyc.springBean.demoBean">bean>
用beanFactory操作bean对象,实现配置,和属性注入
public class MypostProcessBeanFactory implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(
ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("configurableListableBeanFactory" + configurableListableBeanFactory);
// 获取对象
AbstractBeanDefinition demobean =
(AbstractBeanDefinition) configurableListableBeanFactory.getBeanDefinition("demobean");
// 设置初始化方法
demobean.setInitMethodName("init1");
// 注入name值
MutablePropertyValues propertyValues = demobean.getPropertyValues();
propertyValues.add("name", "PostProcessorFactory bane name");
// 设置销毁方法
demobean.setDestroyMethodName("destroy1");
}
}
之后输出查看信息
接下来我们复制一个自定义bean工厂
配置文件新增一个bean
<bean id="mypostProcessBeanFactory2" class="com.hyc.Processor.MypostProcessBeanFactory2"/>
给两个工厂实现优先级接口,设置优先级,
一号工厂优先级为5
二号工厂优先级为10
public class MypostProcessBeanFactory2 implements BeanFactoryPostProcessor, Ordered {
//之前工厂的代码省略
public int getOrder() {
return 10;
}
启动测试
可以看到有级别为5的是线执行的
完美,以上就是用后置处理器来操作bean属性的是实战了
可以监听我们spring中发生的时间,我们也可以自定义一个spring的事件监听器
我们学习这个主要是要知道spring在容器中执行的时候都派发了什么事件
这里我们实现ApplicationListener
这里泛型里的对象是全局的消息,我们也可以写一个自己的自定义的
public class MyApplicationEvent extends ApplicationEvent {
public MyApplicationEvent(Object source) {
super(source);
}
String username;
String emial;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmial() {
return emial;
}
public void setEmial(String emial) {
this.emial = emial;
}
public MyApplicationEvent(Object source, String username, String emial) {
super(source);
this.username = username;
this.emial = emial;
}
}
之后创建新的配置文件 Listener.xml
将事件监听器加入到spring容器中
<bean id="listener" class="com.hyc.listener.myApplicationListener"></bean>
修改事件监听器,让我们来看看是在生成bean的时候都派发了什么事件吧
public class myApplicationListener implements ApplicationListener<ApplicationEvent> {
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接受到的事件" + event);
//这里怕判断是如果有我们自己的定义内容将事件监听器强转成我们的自定监听器,保证自己的自定义事件也可以输出
if (event instanceof MyApplicationEvent) {
MyApplicationEvent myApplicationEvent = (MyApplicationEvent) event;
System.out.println("用户名" + myApplicationEvent.getUsername());
System.out.println("用户邮箱" + myApplicationEvent.getEmial());
}
}
}
之后测试
public class listenerMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext ApplicationContext =
new ClassPathXmlApplicationContext("Listener.xml");
//创建事件对象
MyApplicationEvent event = new MyApplicationEvent("事件内容", "james", "123@qq,com");
//发送事件
ApplicationContext.publishEvent(event);
ApplicationContext.close();
//
}
}
可以看到图中spring的加载过程越来越明显清晰了起来
我们进入调试查看源码
由于源码非常之多,这里就只记录执行过程中做的一些事情
加载过程
新建对象找到spring对象的位置,找到配置文件的位置
之后判断refresh,开始刷新
refresh
spring最核心的方法,refresh都做了什么呢?
首先就是准备刷新:
准备好刷新之后,
准备bean工厂
工厂对象创建
到这里工厂的创建就完成了
注册全部的后置处理器,一般来说。有多少注入的类就有多少后置处理器
执行流程
创建单例对象,不能是懒加载的
resolveBeforeInstantiation
的创建,通过后置处理器,来实现创建代理对象,这一步就是有可能创建对象的,当我们要用aop的时候就用这个方法拿到代理对象.applicationContext
中,至此完成我们创建两个对象,
UserA的构造方法调用UserB对象
循环依赖,
这个是调试断点进入到有参构造方法
如何解决呢?
spring框架的精妙之处,太多值得我们学习,这次的bean的一生只是将思想和大致过程讲解,还有很多需要结合场景的细节,需要我们自己的去探索,不断地深究才可以让自己的技术变得强大