这几天在看雷老师讲的spring注解开发,做了个笔记,在这里记录一下
sping注解开发
@configuration
@conditional
@bean
@Import
一:给容器中注册组件
1)包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
2)@Bean[导入的第三方包里面的组件]
3)@Import[快速给容器中导入一个组件]
1)@Import:容器会自动注册这个组件,id默认是全类名
2)ImportSelector,实现importSelector接口,返回一个类全路径数组,@Import({Color.class,Red.class.MyImportSelector.class})
3) 实现ImportBeanDefinitionRegistrar:手动注册bean到容器中
4) 使用Spring提供的FactoryBean(工厂Bean);
(1)使用spring提供的FactoryBean(工厂 Bean)
(2) 要获取工厂Bean本身,我们需要给id前面 加一个& (&colorFactoryBean)
二.bean的生命周期:
bean的生命周期:
-
构造(对象创建)
- 单实例:在容器启动的时候创建对象
- 多实例:在每次获取的时候创建对象
-
初始化:
- 对象创建完成,并赋值好,调用初始化
-
销毁
- 单实例:容器关闭的时候
- 多实例:容器不会管理这个bean,容器不会调用销毁方法
-
指定初始化和销毁方法
通过@Bean指定init-method和destory-method;
-
通过让Bean实现InitializingBean(定义初始化逻辑),通过实现DisposableBean(定义销毁逻辑)
-
可以使用JSR250;
@PostConstruct:在bean创建完成并且属性赋值完成,来执行初始化方法
@PreDestroy:在容器销毁Bean之前通知我们进行清理
-
BeanPostProcessor[interface] :bean的后置处理器;在bean初始化前后进行一些处理工作
postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之后工作
遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,一旦返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessBeforeInitialization 1.populateBean(beanName,mbd,instanceWrapper) ;给bean复制 initializeBean{ 2.applyBeanPostProcessorBeforeInitialization(wrappedBean,beanNaem); 3.invokeInitMethods(beanName,wrappedBean,mbd);执行初始化方法 4.applyBeanPostProcessorAfterInitialization(wrappedBean,beanName) }
三:Spring底层对postProccessor的使用
BeanValidationPostProcessor
ApplicationContextAwareProcessor
AutowiredAnnotationBeanPostProcessor
Spring底层对BeanPostProcessor的使用
bean赋值。注入其他组件,@Autowired,生命周期注解功能
四,给属性赋值
使用@Value赋值;
- 基本数值
- 可以写SpEL;#{}
- 可以写${};取出配置文件中的值
使用@PropertySource读取外部配置文件中k/v保存到运行的环境变量中
@PropertySource(value={“classpath:/person.properties”})
属性的自动装配
-
@Autowore:自动注入
-
默认优先按照类型去容器中找对应的组件:applicationContext.getBean(Book.Class)
-
如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中国寻找
-
@Qualifier(“bookDao”):使用@Qualifier指定需要装配的组件id
-
自动装配默认一定要将属性赋值好,没有就会报错,可以使用
可以使用@Autowired(required=false);
-
@Primary:让Spring进行自动装配的时候,默认使用首选的bean,也可以继续使用qualifier指定需要装配的Bean的名
-
-
使用AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能
-
@Autowire:构造器,参数,方法,属性
-
自定义组件想要使用Spring容器底层的一些组件(ApplicationContex,BeanFactory,XXX)要实现XXXXAware:在创建对象的时候,会调用想要的方法获取相应的组件
-
@profile :
spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能
- 1.使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
- @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
- 加了环境标识的bean,只有之歌环境被激活的时候才能注册到容器中。默认是default环境
- 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
- 没有标注环境标识的bean在任何环境下都是加载的。
五. AOP面向切面编程
aop:指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;
AOP原理
@EnableAspectJAutoProxy
AnnotationAwareAspectJAutoProxyCreator
-
传入配置类,创建ioc容器
-
注册配置类,调用refresh()刷新容器
-
registerBeanPostProcessors(beanFactory);注册Bean的后置处理器来方便拦截bean的创建
- 先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
- 给容器中加别的BeanPostProcessor
- 优先注册实现了PriorityOrdered接口的BeanPostProcessor
- 再给容器总注册实现了Ordered接口的BeanPostProcessor
- 注册没实现优先级接口的BeanPostProcessor;
- 注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中。
- 创建Bean的实例
- populateBean:给bean的各种属性赋值
- initializeBean:初始化Bean
- invokeAwareMethods():处理Aware接口的方法回调
- applyBeanPostProcessorsBeforeInitialization():应用获知处理器的
- invokeInitMethods();执行自定义的初始化方法
- applyBeanPostProcessorsAfterInitialization()
- BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)
- 把BeanPostProcessor注册到BeanFactory中beanFactory.addBeanPostProcessor(pstProcessor)
-
finishBeanFactoryInitailization(beanFactory);完成BeanFactory初始化工作
-
遍历获取容器中所有的Bean,依次创建getBean(beanName)
getBean->doGetBean->getSingleton()
-
创建bean
-
先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建
-
createBean(),创建Bean,AnnotationAwareAspectJAutoProxyCreator会在任何bean创建之前先尝试返回
BeanPostProcessor是在Bean对象创建完成初始化前后调用的
instantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的。
- resolveBeforeInstantiation(beanName,mbdToUse);希望后置处理器在此返回一个代理对象,如果不能,走下一步:
- doCreateBean()
-
-
AnnotationAwareAspectJAutoProxyCreator[InstantiationAwareBeanPostProcessor]的作用
-
每个Bean创建之前调用调用postProcessBeforeInstantiation();
- 判断当前bean是否在adviseBeans中(保存了所有需要增强Bean)
- 判断当前bean是否是基础类型的Advice,PointCut,Advisor,AopInfrastructureBean,或者是否是切面(@Aspect)
- 是都需要跳过
- 获取候选的增强器(切面里面的通知方法)【List candidateAdvisors】,每个封装的通知方法的增强器是InstantiationModelAwarePointcutAdvisor,判断每个增强器是否是AspectJPointcutAdvisor类型的
- 永远返回false
-
创建对象
postProcessAfterInitialization;
return wrapIfNecessary(bean,beanNaem,cachekey);
-
获取当前bean的所有增强器(通知方法)
-
找到能在当前bean使用的增强器(找哪些通知方法是需要切入当前bean方法的)
-
获取到能在bean使用的增强器
-
给增强器排序
-
保存当前bean在advicedBeans中
-
如果当前bean需要增强,创建当前bean的代理对象
-
获取所哟增强器(通知方法)
-
保存到proxyFactory
-
创建代理对象,Spring自动决定
JdkDynamicAopProxy(config);
ObjenesisCglibAopProxy(config)
-
-
给容器中返回当前组件使用cglib增强的代理对象
-
以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程
目标方法的执行
-
容器中保存组件的代理对象(cglib增强后的对象)
-
CglibAopProxy.intercept()拦截方法的执行
-
根据proxyfactory获取目标方法拦截器链
-
List interceptorList保存了所有的拦截器,一个默认的exposeInvocationInterceptor和4个增强器
-
遍历所有的增强器,将其转为Interceptor;
registry.getInterceptor(advisor)
-
将增强器转为List<MethodInterceptor);如果是MethodIntereptors,直接加入到集合中,如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;转化完成返货MethodInterceptor数组
-
-
如果没有拦截器链,直接执行目标方法
-
如果有拦截器链,吧需要执行的目标对象,目标方法,拦截器链等信息创建一个CglibMethodInvocation对象,并调用 mi.proceed();
-
拦截器链的触发过程
- 如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(制定了最后一个拦截器)执行目标方法
- 链式获取每一个拦截器,拦截器执行invoke方法,每个拦截器等待下一个拦截器执行完成返回结果以后再来执行。
总结:
-
@EnableAspectJAutoProxy开启AOP功能
-
@EnableAspectJAutoProxy会给容器中注册一个组件
-
AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
-
容器的创建流程:
-
registerBeanPostProcessors()注册后置处理器,创建annotationAware
-
finishBeanFactoryInitialization()初始化剩下的单实例bean
-
创建业务逻辑组件和切面组件
-
AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
-
组件创建完之后,判断组件是否需要增强,
是:切面的通知方法,包装成增强器( Advisor);给业务逻辑组件创建一个代理对象
-
-
-
执行目标方法:
-
代理对象目标方法
-
CglibAopProxy.intercept()
-
得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
-
利用拦截器的链式机制,依次进入每一个拦截器进行执行
-
效果:
正常执行:前置通知-》目标方法-》后置通知-》返回通知
出现异常:前置通知-》目标方法-》后置通知-》异常通知
-
-