美文网首页
06-Spring 核心

06-Spring 核心

作者: XAbo | 来源:发表于2022-08-25 14:40 被阅读0次

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的生命周期

  1. 容器初始化: BeanFactory及其子接口和实现类,完成容器初始化并管理Bean的整个生命周期。

  2. Bean定义: BeanDefinitionReader负责加载BeanDefinition(定义方式:编码、XML、注解)。

  3. Bean注册: BeanDefinitionRegistry配合扫描器(如ScannedGenericBeanDefinition)将扫描到的BeanDefinition注册到容器。BeanFactoryPostProcessor 在BeanDefinition注册容器后,读取和修改BeanDefinition。

  4. Bean实例化:
    4.1 Bean实例化前,InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation()。
    4.2 Bean实例化:Spring调用构造方法。
    4.3 Bean实例化后,InstantiationAwareBeanPostProcessor调用postProcessAfterInstantiation()。如果Bean出现循环依赖,则在此阶段之后创建Bean代理对象(即4.4用到了另一个被代理Bean,此时会先会生成该Bean的代理对象,存入二级缓存中后给本Bean的注入)。
    4.4 Bean属性注入前InstantiationAwareBeanPostProcessor调用postProcessProperties();如果4.3返回false,该4.4不会被调用(会跳过依赖注入)。
    4.4 Bean属性注入:给Bean属性进行赋值。

  5. Bean初始化:
    5.1 Bean初始化前,Aware可获取spring的容器,然后获得相关的Bean。
    5.2 Bean初始化前,BeanPostProcessor添加自己的Before逻辑。
    5.3 Bean初始化前,InitializingBean执行特定业务化的操作。
    5.4 Bean的初始化,init方法执行。
    5.5 Bean初始化后,BeanPostProcessor添加自己的After逻辑。正常情况下如果Bean需要被代理,就是在此阶段进行。

  6. Bean的AOP: 提供代理Bean,增强可被重写方法的功能。注意Spring中只存储代理后的对象。代理对象与目标对象是两个不同的对象,不会共享成员变量。代理对象也不会走前面的流程。

  7. Bean的使用: 单例对象会放入BeanFactory池中。

  8. Bean的销毁:
    8.1 Bean销毁前,DisposableBean获得一次回调。
    8.2 Bean的销毁,destroy方法执行。

Bean的初始化和销毁的方式:

初始化:
1.@Bean指定init-method
2.实现InitializingBean
3.@PostConstruct
4.BeanPostProcessor
销毁:
1.@Bean指定destroy-method
2.实现DisposableBean
3.@PreDestroy

InitializingBean和BeanPostProcessor区别:
BeanPostProcessor对所有Bean都有作用而InitializingBean、Aware是对实现本接口的Bean起作用。

实现InstantiationAwareBeanPostProcessor和BeanPostProcessor的Bean,后处理器自身的方法为什么不会被调用?
答:后处理器的注册前提是完成了后处理器的实例化;而Bean的注册不需要实例化。

1.完成Bean的注册。
2.实例化前:不会执行InstantiationAwareBean后处理器的方法,
  是由于此时本身还没实例化,且没有被注册“后处理器”。
3.实例化:完成Bean的实例化。此时才有注册“后处理器”的资格。
4.初始化前:不会执行BeanPost后处理器的方法,是由于没有被注册成为“后处理器”。
5.完成Bean初始化。
6.注册成为“后处理器”。

三、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执行调用链。

MethodInterceptor的proceed()递归:实现链调用链

Spring常用工具类:https://www.cnblogs.com/q1359720840/p/16291116.html

相关文章

  • 06-Spring 核心

    Spring做了两件事:1.管理Bean的生命周期 2. 创建Bean的代理对象 一、Spring容器 1.1 ...

  • 06-Spring jdbcTemplate

    一、jdbcTemplate的基本使用: Account: JdbcTemplateDemo1 : 二、jdbcT...

  • 06-spring源码解析之声明式事务

    声明式事务:环境搭建: 导入相关依赖:数据源,数据驱动, Spring-jdbc模块2.配置数据源,JdbcTem...

  • 挤进核心,成为核心

    没想到生平第一次用Skype,会是一场跨国面试。 结果是,初面挺好的,Skype的使用体验也不错。除了中途网络原因...

  • 核心——核心才是关键

    瑜伽老师讲,我们练习瑜伽最关键的是核心,只有核心稳定了,能量强大了,其他的便会与之环绕。这便是瑜伽的智慧,她充分了...

  • 156/365 研修 素养为纲,育人为本——课标研制思路

    跨学科核心素养包括: 语文核心素养,历史核心素养,物理核心素养,数学核心素养。 什么是学科核心素养? 个体在面对复...

  • 核心?核心肌群?核心稳定性?核心力量?这几个你分清楚了吗?

    平板支撑练核心!稳定核心!收紧核心!这样的说法你应该总能听见。那么核心究竟是什么?核心肌群、核心稳定性、核心力量又...

  • 酒店的核心产品是什么?答案你想象不到!(上)

    核心产品是什么,核心定位、核心设计、核心文化,还有核心管理、核心价值,这是酒店我认为是几个比较重要的方面, 酒店...

  • 核心

    古交给排水公司党总支部,下设机关、自来水厂、污水处理厂、净化水厂四个党支部,共有60余名党员。多年来,公司充分发挥...

  • 核心

    在瑜伽体式中;经常有“守好核心”这样的口令提醒;身体需要核心力量的支持和稳定;联想到内在如是… 每个人都在寻找平衡...

网友评论

      本文标题:06-Spring 核心

      本文链接:https://www.haomeiwen.com/subject/gxwtnrtx.html