Spring做了两件事:1.管理Bean的生命周期 2. 创建Bean的代理对象
一、Spring容器
1.1 BeanFactory接口
BeanFactory接口表面只定义了获取Bean的方法,但是其实现类实际上负责了IOC、DI和管理Bean的生命周期。
实现类:DefaultListableBeanFactory
1.读取Bean的定义只能通过registerBeanDefinition()以编码的形式。
2.手动添加后处理器;如果要支持注解等扩展功能,只能通过AnnotationConfigUtils手动添加。
3.不会主动实例化单例对象。
Spring容器,从根源上是由BeanFactory接口的实现类DefaultListableBeanFactory实现的;它是真正可以作为一个独立容器使用的类。
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", beanDefinition);
// 给 BeanFactory添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 从bean工厂中取出BeanFactory的后处理器,并且执行这些后处理器
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
System.out.println(beanFactoryPostProcessor);
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
// 打印BeanFactory中Bean
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
// 要想@Autowired、@Resource等注解被解析,还要添加Bean的后处理器,可以针对Bean的生命周期的各个阶段提供扩展
beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).collect(Collectors.toCollection(ArrayList::new)));
// 通过AnnotationConfigUtils给beanFactory添加一些后处理的时候会默认设置比较器,可以对BeanPostProcessor进行排序,排序的依据是BeanPostProcessor内部的order属性,其中internalAutowiredAnnotationProcessor的order属性的值为Ordered.LOWEST_PRECEDENCE - 2,internalCommonAnnotationProcessor的order属性的值为Ordered.LOWEST_PRECEDENCE - 3
System.out.println("internalAutowiredAnnotationProcessor:" + (Ordered.LOWEST_PRECEDENCE - 2));
System.out.println("internalCommonAnnotationProcessor:" + (Ordered.LOWEST_PRECEDENCE - 3));
// DefaultListableBeanFactory不会主动初始化单例,所以:准备好所有单例,get()前就把对象初始化好
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Bean1 bean1 = beanFactory.getBean(Bean1.class);
System.out.println(bean1.getBean2());
System.out.println(bean1.getInter());
}
1.2 ApplicationContext接口
ApplicationContext接口比BeanFactory接口多4个接口的功能:
1.EnvironmentCapable:获取环境变量,可以通过ApplicationContext获取操作系统环境变量和JVM环境变量。
2.MessageSource:ApplicationContext继承了这个接口,就拥有了国际化功能,比如可以直接利用MessageSource对象获取某个国际化资源。
3.ResourcePatternResolver:ApplicationContext继承了这个接口,就拥有了加载并获取资源的功能,这里的资源可以是文件,图片等某个URL资源都可以。
4.ApplicationEventPublisher:ApplicationContext继承了这个接口,就拥有了事件发布功能,可以发布事件,这是ApplicationContext相对于BeanFactory比较突出、常用的功能。
1.实现类:ClassPathXmlApplicationContext和FileSystemXmlApplicationContext
1.读取Bean的定义以XML的形式。
2.如果要支持注解功能,只能通过<context:annotation-config/>。
3.主动实例化单例对象。
DefaultListableBeanFactory+XmlBeanDefinitionReader;基于类/磁盘路径下XML格式的配置文件创建容器;
2.实现类:AnnotationConfigApplicationContext
1.读取Bean的定义以配置类的形式。
2.默认要支持注解。
3.主动实例化单例对象。
基于JAVA的配置类进行容器的创建。
3.实现类:AnnotationConfigServletWebServerApplicationContext
基于JAVA的配置类进行容器的创建,模拟了 springboot:用于WEB环境(SpringMVC)。可以内嵌Web容器(个人理解就是用来将Spring容器放到ServletContext)和DispatcherServlet(解析HTTP请求)。
// 模拟了 springboot web项目内嵌Tomcat的工作原理
public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
// 防止程序终止
System.in.read();
}
@Configuration
class WebConfig {
@Bean
// 1. WebServer工厂
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
@Bean
// 2. web项目必备的DispatcherServlet
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
// 3. 将DispatcherServlet注册到WebServer上
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1() {
return (request, response) -> {
response.getWriter().println("hello");
return null;
};
}
}
4.实现类:GenericApplicationContext
1.它不预设指定任何bean定义格式(例如XML或注释)。
2.refresh()会自动执行添加的BeanFactory后处理器和Bean后处理器。
3.会初始化所有单例。
实现内部有一个DefaultListableBeanFactory实例。可以采用混合方式处理bean的定义,而不是采用特定的bean定义方式来创建bean。
二、Bean的生命周期
2.1.Bean定义阶段
- 寻找所有的BeanDefinition。
- 寻找所有的
BeanFactoryPostProcessor
和BeanPostProcessor
并实例化,包含Spring内置和自定义的后置器。 - 执行内置的BeanFactoryPostProcessor完成对BeanDefinition扩展,如ConfigurationClassPostProcessor解析@ComponentScan、@Bean、@Import、@ImportResource。
- 执行自定义的BeanFactoryPostProcessor完成对BeanDefinition扩展。
2.2.Bean实例化阶段
- BeanFactory根据扩展后的BeanDefinition完成对所有的Bean的实例化。
2.3.Bean初始化前阶段
- 执行内置的BeanPostProcessor完成对Bean属性注入等操作,如AutowiredAnnotationBeanPostProcessor解析@Autowired与@Value对Bean的属性进行注入。
- 执行自定义的BeanPostProcessor完成对Bean自定义的操作。
2.4.Bean初始化阶段
- 执行Bean的初始化方法。 1.@Bean指定init-method 2.实现InitializingBean 3.@PostConstruct
2.5.Bean初始化后阶段
- 执行内置的BeanPostProcessor完成对BeanAOP等操作。
- 执行自定义的BeanPostProcessor完成对Bean自定义的操作。
2.6.Bean使用和销毁
销毁:1.@Bean指定destroy-method 2.实现DisposableBean 3.@PreDestroy
@Autowired失效类问题
BeanFactoryPostProcessor
的定义信息在某个配置类(Bean)中,该Bean中有某些属性是需要@Autowired注入的。
失效原因:Spring在Bean定义阶段去实例化对应BeanFactoryPostProcessor时候, 会对先对配置类(Bean)实例化,实例化后按照Spring的流程走,应该执行AutowiredAnnotationBeanPostProcessor去解析@Autowired。但是此时AutowiredAnnotationBeanPostProcessor没有被发现更没有被实例化。所以此时没人认识@Autowired,导致@Autowired修饰的属性无法注入。
解决该类问题 :使用编码方式,让Bean实现Aware类或InitializingBean接口,属性手动进行属性注入。Aware或InitializingBean接口执行的顺序参考上图。
三、AOP
1.AOP的实现方式:proxy、Aspectj、agent
-
Aspectj
:编译器在编译阶段改写class文件,需要使用Aspectj插件。 -
agent
:JVM加载class过程中改写class文件。 -
proxy
:运行时生成代理对象;不能代理静态方法;其实现方式:JDK和CGLIB;
JDK:实现同一个接口;代理对象与原对象是兄弟关系,不能互转。
CGLIB:利用继承关系,重写父类方法;代理对象与原对象是父子关系,可以互转,但父类不能为final。
proxy的两种方式,为了优化避免利用反射回调被代理对象的方法,采用的优化手段有区别。
Spring的AOP:JDK或CGLIB
public class Aop {
public static void main(String[] args) {
//1.准备切点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution (* foo())");
//2.准备通知
MethodInterceptor advice = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before ^" );
invocation.proceed();
System.out.println("after ^" );
return null;
}
};
//3.准备切面
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,advice);
// 4.创建代理
Target target= new Target();
ProxyFactory factory = new ProxyFactory();
//proxyTargetClass = false,且目标实现了接口,使用JDK。
//proxyTargetClass = false,且目标没有实现接口,使用CGLIB。
//proxyTargetClass = trun,直接使用CGLIB。
factory.setProxyTargetClass(false);
factory.setTarget(target);
factory.addAdvisor(advisor);
Target proxy = (Target)factory.getProxy();
proxy.foo();
}
static class Target {
public void foo(){
System.out.println("foo……");
}
}
}
2. AOP的组成部分:切点、通知以及通知类型
对于日志的注解案例,以Logger类:
1.通知:即方法本身。
2.通知类型:在方法上注解。
3.切点:在Logger类或者方法(通知)上设置切点表达式。
对于Spring事务的注解案例,事务的通知类是在jar包中,导致:
1.通知:即方法本身,Spring已经固定。
2.通知类型:Spring使用环绕通知。
3.切点:只能在目标方法上添加事务注解@Transactional。
3.Spring的AOP切面的细节
1.会将高级切面转换为基本的切面类。
2.对基本切面排序后将所有非环绕通知转换为环绕通知。
3.经过适配器转换后,MethodInterceptor执行调用链。
Spring常用工具类:https://www.cnblogs.com/q1359720840/p/16291116.html