spring源码
spring源码
一、IOC模块:组件注册
1.原始方式,是通过配置xml配置文件,写bean类。使用如下ClassPathXmlApplicationContext获取类。
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
RegisterDAO registerDAO = (RegisterDAO)ac.getBean("RegisterDAO");
2.注解方式,通过@Configuration+@Bean的方式。其中@Scope可以配置单例(只需一份实例)还是多例(适用于并发环境,但其实我们还是更倾向于使用代码控制并发),request还是session。区别:单例在spring启动时,不管调不调用直接进入spring容器(因为是单实例嘛,所以干脆直接加入了)。而多例只在使用时才加入,且每次使用都会初始化一个新的类。
由此才有了@Lazy去懒加载,保证默认的单例不会加入容器,只有使用时才会。
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
//ctx.register(AppConfig.class);相当于读哪份配置文件
ctx.refresh();
Entitlement ent = (Entitlement)ctx.getBean("entitlement");
重点:@Component主要注入自己写的类交给spring管理,@Bean注入第三方包交给spring管理。
但是实际上对于无参的第三方包可以直接通过@import(类.class)导入,方便多了
3.包扫描作用:让@Component,@Controller这些注解自动注入spring管理,并且自动装配。否则得用application对象完成这些操作。
同样的,xml需要有一句话配置,注解也需要有个注解。@ComponentScan
@ComponentScan(里面的确还有很多配置,比如扫描的包,去除和只包含哪些)其实注解里面方法就是这样配置 方法名=””
@ComponentScan(value = "com.nrsc.springstudy.c1_componentscan1.study2.config2_test",
includeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = {Component.class})},
useDefaultFilters = false)
总结:
1.配置的所有@Component等注解,spring不能主动进行管理。所以得要我们告诉他哪些需要管理,所以才有了@ComponentScan。
二、生命周期
可自定义bean的初始化和销毁。@Bean(initMethod= ,destoryMethod=)
1.通过@Bean注解中配置初始化和销毁的方法。(单例是执行初始化和销毁的方法。但是多例是不会调用销毁方法,spring要求自己销毁)
2.通过bean实现接口initializingBean,afterPropertieset()方法定义初始化,通过实现DisposableBean接口,destory()定义销毁方法。
(Timing:对象创建并赋值之后)
3.@PostConstruct配置初始化,@PreDestory配置销毁
(Timing:对象创建并赋值之后)
4.bean的后置处理器beanPostProcessor接口。postProcessBeforeInitialization,postProcessAfterInitialization
(Timing:对象创建并赋值之后,在其他任何初始化调用之前,在初始化调用之后。初始化前后。作用:在bean初始化前后完成操作)
注:1.spring底层用beanPostProcessor也用的非常多。2.必须在对象装配完属性之后
大概过程:
-
bean实例化
finishBeanFactoryInitialization getBean(就是doGetBean,只是一层包装) doGetBean getSingleton createBean doCreateBean(包含了populateBean,initializeBean的全过程,即使通过这个方法来完成后面的方法) 以下是2,3,4是docreateBean中的执行方法。
-
createBeanInstance 通过bean的name得到一个BeanWrapper,通过这个调用getWrappedInstance就可以得到我们要的bean。
-
属性赋值 Populate populateBean() -> 属性赋值 (AutowiredAnnotationBeanPostProcessor,一般是这个进行属性装配)
-
初始化 Initialization initializeBean() -> 初始化 (上面的4种方法都是围绕这个)
initializeBean的过程如下:
applyBeanPostProcessorsBeforeInitialization 遍历取出所有的beanPostProcessor,进行执行相应的前置处理 invokeInitMethods 初始化方法(就是我们定义的前几种初始化的方法,执行init-method、postConstract注解的方法、afterPropertiesSet) applyBeanPostProcessorsAfterInitialization 遍历取出所有的beanPostProcessor,进行执行相应的后置处理
-
销毁 Destruction
bean的赋值(@value),注入其他组件(xxxAware所有接口),@Autowired(AutowiredAnnotationBeanPostProcessor,其实查看源码可以发现,他还支持@value,@autowired,@inject),生命周期注解功能(@PostConstruct属于InitDestroyAnnotationBeanPostProcessor)…..等等功能,都是beanPostProcessor的实现类实现的。
三、快速获取application对象
1.实现Spring的ApplicationContextAware接口,重写setApplicationContext方法,将得到的ApplicationContext对象保存到一个静态变量中,有了这个上下文对象,就可以在项目的任意地方用它来得到任意Bean;
2.直接注入对象
@Autowired
private ApplicationContext applicationContext;
四、属性赋值(AutowiredAnnotationBeanPostProcessor)
1.@Vlaue(${}):取出配置文件中的值(可以指定读取配置)。@Vlaue(#{}):使用Spel表达式取值
2.@Autoired:默认是按类型去容器中找组件。如果找到多个,默认按属性名作为id。加上@Qualifer可以直接指定名字。默认必须装配成功,装配失败则报错。当然里面也有属性可以配置。@Autowired(required =false)
3.@Resource java规范注解,仅提供按名称注入。
4.@Inject java规范注解额,需要额外导包,和@Autoired效果一样。但是不支持required。
重点介绍:@Autoired
作用域:@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
即可以加到构造器,方法,属性等上。
@Autoired//加在方法上,传入的参数从容器中拿。加在参数上也是一样。用构造器也是这样,但是对于只有一个有参构造器,可以省略注解
public void setCar(Car car){
this.car=car;
}
5.获取spring底层组件,实现XXXAware接口。(Aware类型的接口可以得到很多spring的组件)
如:ApplicationContextAware,BeanFactoryAware等。也不难,在实现这些接口,都会要求重写set方法,底层无非就是通过判断当前类是否实现了XXXAware,如果是,则调用刚才实现的set方法进行注入。
底层依赖ApplicationContextAwareProcessor,是BeanPostProcessor的实现类。所以对于获得spring底层组件的类基本都是利用了BeanPostProcessor,且多以XXXAware结尾。并在postProcessBeforeInitialization中进行判断是否是ApplicationContextAware类(里面还判断是否其他类,如上下文环境等),如果是,则赋值applicationContext。
对于这类方法必定会有一个setxxxxx()方法。用于注入对象。
五、AOP
JoinPoint这个参数必须写参数表的第一位,写在后面无法生效。
1.写切面记得用@Aspect。
2.在切面的通知方法中必须标注注解,并写切入点表达式。
3.开启aop注解模式@EnableAspectJAutoProxy,不然上面注解都不能生效。
源码:@EnableAspectJAutoProxy做了哪些事?
通过导入@Import(AspectJAutoProxyRegistrar.class),这个类创建一个自动代理创建器AnnotationAwareAspectJAutoProxyCreator。
可以发现最后还是实现了BeanPostProcessor接口和Aware接口。