aoe1231

知之为知之,不知为不知

Spring高级 - 第1部分

1、容器接口

1.1、BeanFactory功能

1.1.1、什么是 BeanFactory ?

BeanFactory:

  • 是 ApplicationContext 的父接口
  • 是 Spring 的核心容器,主要的 ApplicationContext 实现都【组合】了它的功能

从上面类继承图可以看到,ApplicationContext继承了BeanFactory,即ApplicationContext对BeanFactory提供了一些功能上的拓展,这些功能拓展就是继承右侧的那些父接口,比如MessageSource、ResourcePatternResolver、ApplicationEventPublisher、EnvironmentCapable。

其中BeanFactory接口有一些getBean()方法用于获取Bean对象:

public interface BeanFactory {
    // ...

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
    
    // ...
}

因此ConfigurableApplicationContext也具备这些方法。编写以下代码,并查看getBean()方法的具体实现:

/**
 * SpringBoot 启动类
 */
@SpringBootApplication
public class SpringSourceStudyApplication {

    public static void main(String[] args) {
        // 返回的对象就是Spring容器对象, 选中该类,按住ctrl+alt+u,可以打开类图
        ConfigurableApplicationContext caContext = SpringApplication.run(SpringSourceStudyApplication.class, args);

        // 对下面的方法按住ctrl+alt+单击,可以进入其实现类的对应方法
        caContext.getBean("aaa");

        System.out.println(caContext);
    }

}
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    // ...
    
    public Object getBean(String name) throws BeansException {
        this.assertBeanFactoryActive();
        // 这里是获取了BeanFactory再调用它的getBean()方法,说明它内部的功能拓展是组合了一个BeanFactory作为成员变量,getBean()功能由这个BeanFactory提供
        return this.getBeanFactory().getBean(name);
    }
    
    // ...
}

1.1.2、BeanFactory能干点啥?

回到BeanFactory接口的定义:

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    // 根据Bean名称判断容器中是否包含这个Bean对象
    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    // 根据Bean名称获取它的别名
    String[] getAliases(String var1);
}

虽然BeanFactory表面上只有一些getBean()方法,实际上控制反转、基本的依赖注入、Bean的生命周期的各种功能,都由它的实现类提供。比如DefaultListableBeanFactory,下面是它的类结构图:

从上面类图可以看出,DefaultListableBeanFactory是DefaultSingletonBeanRegistry的子类,继承了它的管理单例对象的功能,并且实现了ConfigurableListableBeanFactory接口,在DefaultSingletonBeanRegistry中定义了字段singletonObjects用来存储单例的Bean对象:

为了证明这一点,我们编写一个单例对象并放入Spring容器中:

@Slf4j
@Component
public class Component1 {
}

我们尝试直接从singletonObjects属性中去获取这个Bean,因为singletonObjects属性是私有的,我们可以通过反射来获取:

/**
 * SpringBoot 启动类
 */
@SpringBootApplication
public class SpringSourceStudyApplication {

    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
        // 返回的对象就是Spring容器对象, 选中该类,按住ctrl+alt+u,可以打开类图
        // 这里返回的实现类为 AnnotationConfigServletWebServerApplicationContext
        ConfigurableApplicationContext caContext = SpringApplication.run(SpringSourceStudyApplication.class, args);

        // 获取caContext的BeanFactory,这里返回的实现类为 DefaultListableBeanFactory
        ConfigurableListableBeanFactory beanFactory = caContext.getBeanFactory();
        
        // 反射获取 beanFactory 的 singletonObject 字段,它是一个Map<String, Object>
        Field fSingletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        fSingletonObjects.setAccessible(true);
        Map<String, Object> map = (Map<String, Object>) fSingletonObjects.get(beanFactory);
        
        // 查询 singletonObjects 集合,找到我们定义的 Bean
        map.forEach((k, v) -> {
            if (v instanceof Component1) {
                System.out.println(k + "=" + v);
            }
        });
    }

}

结果:
component1=com.clp.components.Component1@272a179c

1.2、ApplicationContext功能

我们查看ApplicationContext类图:

BeanFactory 和 ApplicationContext 并不仅仅是简单接口继承的关系,ApplicationContext 组合并扩展了 BeanFactory 的功能。

它分别继承了MessageSource、ResourcePatternResolver、ApplicationEventPublisher、EnvironmentCapable接口来扩展功能,接下来分别看一下这几个父接口都有什么样的功能。

1.2.1、父接口 - MessageSource

其中MessageSource接口定义如下:

public interface MessageSource {
    // 根据 code 返回不同语言版本的翻译后结果
    @Nullable
    String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);

    String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;

    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}

这个接口的功能是根据键找到不同语言版本的翻译后结果,翻译信息需要我们自己定义在配置文件中,SpringBoot默认配置在名称如 messages.properties、messages_en.properties、messages_ja.properties 、message_zh.properties 等等的配置文件中,其中 messages.properties 存储通用的翻译结果,message_en.properties 为存储英文的翻译结果,message_zh.properties存储中文的翻译结果等等。

比如我们要编写键为“code_hello”的英文翻译结果,可以在message_en.properties中编写如下内容:

code_hello=hello

而要编写该键的中文翻译结果,可以在message_cn.properties中编写如下内容:

code_hello="你好"

我们尝试通过ApplicationContext获取翻译结果:

/**
 * SpringBoot 启动类
 */
@SpringBootApplication
public class SpringSourceStudyApplication {

    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
        // 这里返回的实现类为 AnnotationConfigServletWebServerApplicationContext
        ConfigurableApplicationContext caContext = SpringApplication.run(SpringSourceStudyApplication.class, args);

        ApplicationContext aContext = caContext;
        String msgHello = caContext.getMessage("code_hello", null, Locale.CHINA); // 会从messages_zh.properties读取
        System.out.println(msgHello);
    }

}

结果:
"你好"

1.2.2、父接口 - ResourcePatternResolver & EnvironmentCapable

ResourcePatternResolver 用于加载和解析资源文件。

/**
 * SpringBoot 启动类
 */
@SpringBootApplication
public class SpringSourceStudyApplication {

    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException, IOException {
        // 这里返回的实现类为 AnnotationConfigServletWebServerApplicationContext
        ConfigurableApplicationContext caContext = SpringApplication.run(SpringSourceStudyApplication.class, args);

        ApplicationContext aContext = caContext;

        /**
         * ResourcePatternResolver 可以获取类路径的资源文件:
         */
        Resource[] resources1 = aContext.getResources("classpath:application.properties");
        for (Resource resource : resources1) {
            System.out.println(resource);
        }

        /**
         * classpath 和 classpath* 区别:
         *  classpath:只会到你的class路径中查找找文件。
         *  classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找。
         * 注意: 用classpath*:需要遍历所有的classpath,所以加载速度是很慢的;
         *  因此,在规划的时候,应该尽可能规划好资源文件所在的路径,尽量避免使用classpath*。
         */
        Resource[] resources2 = aContext.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources2) {
            System.out.println(resource);
        }
    }
}

结果:
class path resource [application.properties]
URL [file:/G:/Study/Java/java-study/spring-source-study/target/classes/META-INF/spring.factories]
URL [jar:file:/G:/Tools/apache-maven-3.6.1/mvn_repository/org/springframework/boot/spring-boot/2.6.13/spring-boot-2.6.13.jar!/META-INF/spring.factories]
URL [jar:file:/G:/Tools/apache-maven-3.6.1/mvn_repository/org/springframework/boot/spring-boot-autoconfigure/2.6.13/spring-boot-autoconfigure-2.6.13.jar!/META-INF/spring.factories]
URL [jar:file:/G:/Tools/apache-maven-3.6.1/mvn_repository/org/springframework/spring-beans/5.3.23/spring-beans-5.3.23.jar!/META-INF/spring.factories]

1.2.3、父接口 - EnvironmentCapable

EnvironmentCapable 可以获取环境变量、配置信息。

/**
 * SpringBoot 启动类
 */
@SpringBootApplication
public class SpringSourceStudyApplication {

    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException, IOException {
        // 这里返回的实现类为 AnnotationConfigServletWebServerApplicationContext
        ConfigurableApplicationContext caContext = SpringApplication.run(SpringSourceStudyApplication.class, args);

        ApplicationContext aContext = caContext;

        /**
         * environment 用于获取配置信息,包括环境变量、application.properties中的配置属性
         */
        ConfigurableEnvironment environment = aContext.getEnvironment();
        System.out.println(environment.getProperty("java_home"));
        System.out.println(environment.getProperty("server.port"));
    }
}

结果:
D:\jdks\jdk1.8
8080

1.2.4、父接口 - ApplicationEventPublisher

用于推送事件。将事件发布者和接收者进行解耦。

代码演示1:

@Slf4j
@Component
public class Component2 {
    /**
     * 添加 @EventListener 表示该方法会监听事件
     * @param event 监听的事件类型
     */
    @EventListener
    public void aaa(UserRegisterEvent event) {
        log.info("{}", event);
    }
}

/**
 * SpringBoot 启动类
 */
@SpringBootApplication
public class SpringSourceStudyApplication {

    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException, IOException {
        // 这里返回的实现类为 AnnotationConfigServletWebServerApplicationContext
        ConfigurableApplicationContext caContext = SpringApplication.run(SpringSourceStudyApplication.class, args);

        ApplicationContext aContext = caContext;

        // 发布事件,所有监听这个事件的对象都会被通知
        aContext.publishEvent(new UserRegisterEvent(aContext));
    }
}

结果:
2023-04-10 10:10:47.477  INFO 24060 --- [           main] com.clp.components.Component2            : com.clp.UserRegisterEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@367ffa75, started on Mon Apr 10 10:10:46 CST 2023]

代码演示2:

/**
 * 模拟事件发布者
 */
@Slf4j
@Component
public class Component1 {
    /**
     * 手动注入 应用事件发布器 对象
     */
    @Autowired
    private ApplicationEventPublisher context;

    /**
     * 模拟用户进行注册,并发布用户注册事件
     */
    public void register() {
        log.info("用户注册");
        context.publishEvent(new UserRegisterEvent(this));
    }
}

/**
 * 模拟事件监听者
 */
@Slf4j
@Component
public class Component2 {

    /**
     * 添加 @EventListener 表示该方法会监听事件
     * @param event 监听的事件类型
     */
    @EventListener
    public void aaa(UserRegisterEvent event) {
        log.info("{}", event);
        log.info("发送短信...");
    }
}

/**
 * SpringBoot 启动类
 */
@SpringBootApplication
public class SpringSourceStudyApplication {

    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException, IOException {
        // 这里返回的实现类为 AnnotationConfigServletWebServerApplicationContext
        ConfigurableApplicationContext caContext = SpringApplication.run(SpringSourceStudyApplication.class, args);

        ApplicationContext aContext = caContext;

        // 方式2:
        aContext.getBean(Component1.class).register();
    }
}

结果:
2023-04-10 10:20:22.329  INFO 7088 --- [           main] com.clp.components.Component1            : 用户注册
2023-04-10 10:20:22.330  INFO 7088 --- [           main] com.clp.components.Component2            : com.clp.UserRegisterEvent[source=com.clp.components.Component1@4d847d32]
2023-04-10 10:20:22.330  INFO 7088 --- [           main] com.clp.components.Component2            : 发送短信...

2、容器实现

2.1、BeanFactory 实现

先看以下代码演示:

public class TestBeanFactory {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 1、添加Bean 的定义(Bean定义包含:class、scope、初始化方法、销毁方法等信息)
        // 1.1、创建 Bean定义(通过Builder)
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
                .setScope("singleton").getBeanDefinition();
        // 1.2、将 Bean定义 注册到 Bean工厂
        beanFactory.registerBeanDefinition("config", beanDefinition);

        // 循环查找 Bean工厂 中所有 Bean定义
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    @Slf4j
    static class Bean1 {
        public Bean1() {
            log.info("构造 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

    @Slf4j
    static class Bean2 {
        public Bean2() {
            log.info("构造 Bean2()");
        }
    }
}

结果:
config

这里控制台只打印了 config,并没有打印 @Bean 注解的 Bean1 和 Bean2,说明 BeanFactory 并没有解析 Config 类的 @Configuration 注解,也即缺少解析 @Bean 的能力,功能不完整。

下面代码使用了Bean工厂处理器对Bean工厂的功能进行了补充:

public class TestBeanFactory {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 1、添加Bean 的定义(Bean定义包含:class、scope、初始化方法、销毁方法等信息)
        // 1.1、创建 Bean定义(通过Builder)
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
                .setScope("singleton").getBeanDefinition();
        // 1.2、将 Bean定义 注册到 Bean工厂
        beanFactory.registerBeanDefinition("config", beanDefinition);

        // 2、使用 后处理器 扩展 BeanFactory 的功能,下面的代码给 BeanFactory 补充了 Bean1 和 Bean2 的定义
        // 使用工具类,该方法的作用是给 BeanFactory 添加一些常用的(内置)后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        // 执行 Bean工厂后处理器(后处理器执行后, Config 的 @Bean 会生效)
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });

        // 循环查找 Bean工厂 中所有 Bean定义
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 检查 Bean1 是否成功注入了 Bean2,发现并没有成功注入
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    @Slf4j
    static class Bean1 {
        public Bean1() {
            log.info("构造 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

    @Slf4j
    static class Bean2 {
        public Bean2() {
            log.info("构造 Bean2()");
        }
    }
}

结果:
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2
10:54:52.759 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
10:54:52.761 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
10:54:52.775 [main] INFO com.clp.TestBeanFactory$Bean1 - 构造 Bean1()
null

上面代码我们发现使用了 Bean工厂处理器 的postProcessBeanFactory() 之后 Config 类的 @Bean 配置生效了,但是 Bean1 并没有成功注入 Bean2。

下面代码使用了 Bean处理器 对 Bean 的注解进行了处理:

public class TestBeanFactory {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 1、添加Bean 的定义(Bean定义包含:class、scope、初始化方法、销毁方法等信息)
        // 1.1、创建 Bean定义(通过Builder)
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
                .setScope("singleton").getBeanDefinition();
        // 1.2、将 Bean定义 注册到 Bean工厂
        beanFactory.registerBeanDefinition("config", beanDefinition);

        // 2、使用 后处理器 扩展 BeanFactory 的功能,下面的代码给 BeanFactory 补充了 Bean1 和 Bean2 的定义
        // 使用工具类,该方法的作用是给 BeanFactory 添加一些常用的(内置)后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        // 执行 Bean工厂后处理器(后处理器执行后, Config 的 @Bean 会生效)
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });

        // 3、使用 Bean后处理器,针对 Bean 的生命周期各个阶段提供扩展,例如对 @Autowired、@Resource ... 的解析
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });

        // 循环查找 Bean工厂 中所有 Bean定义
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 检查 Bean1 是否成功注入了 Bean2,这次成功注入了
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    @Slf4j
    static class Bean1 {
        public Bean1() {
            log.info("构造 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

    @Slf4j
    static class Bean2 {
        public Bean2() {
            log.info("构造 Bean2()");
        }
    }
}

结果:
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2
11:02:22.912 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
11:02:22.914 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
11:02:22.932 [main] INFO com.clp.TestBeanFactory$Bean1 - 构造 Bean1()
11:02:22.949 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
11:02:22.949 [main] INFO com.clp.TestBeanFactory$Bean2 - 构造 Bean2()
com.clp.TestBeanFactory$Bean2@7bb58ca3

上面的代码我们发现,BeanFactory 仅仅是保存了 BeanDefinition,并且只有在调用 getBean() 方法后才对 Bean 进行了实例化。我们可以直接调用下面的方法(在 ConfigurableListableBeanFactory 接口中定义)来手动提前创建所有的单例对象:

// 提前创建所有单例对象
beanFactory.preInstantiateSingletons();

总结:

  • BeanFactory不会做的事:① 不会主动调用 BeanFactory 后处理器;② 不会主动添加 Bean 后处理器;③ 不会主动初始化单例;④ 不会解析 BeanFactory,还不会解析 ${} 与 #{}。
  • Bean后处理器会有排序的逻辑。
  • @Autowired实现逻辑:先匹配类型,如果有多个Bean匹配上,那么再检查变量名称,如果名称有匹配上的Bean会使用这个Bean。

2.2、ApplicationContext 实现

@Slf4j
public class TestApplicationContext {

    @Slf4j
    static class Bean1 {
    }

    @Slf4j
    static class Bean2 {
        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }

    public static void main(String[] args) {
//        testClassPathXmlApplicationContext();
//        testFileSystemXmlApplicationContext();
//        testAnnotationConfigApplicationContext();
        testAnnotationConfigServletWebServerApplicationContext();
//        xmlprinciple();

    }

    // 1、较为经典的容器,基于 classpath 下 xml 格式的配置文件来创建
    private static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());

        /** 打印结果:
         *      bean1
         *      bean2
         *      com.clp.TestApplicationContext$Bean1@6a1aab78
         */
    }

    // 2、基于磁盘路径下的 xml 格式的配置文件来创建
    private static void testFileSystemXmlApplicationContext() {
        // 绝对路径写法。如要使用相对路径写法,则从模块路径开始,即 src\main\resources\spring-config01.xml
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
                "G:\\Study\\Java\\java-study\\spring-source-study\\src\\main\\resources\\spring-config01.xml"
        );
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());

        /** 打印结果:
         *      bean1
         *      bean2
         *      com.clp.TestApplicationContext$Bean1@6a1aab78
         */
    }

    // 基于 xml 文件的 ApplicationContext 实现原理:
    private static void xmlprinciple() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取之前...");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println("读取之后...");
        // 使用 XmlBeanDefinitionReader 来进行解析
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // 此处为类路径资源,如果是系统路径资源则是 new FileSystemResource("G:\\Study\\Java\\java-study\\spring-source-study\\src\\main\\resources\\spring-config01.xml")
        reader.loadBeanDefinitions(new ClassPathResource("spring-config01.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        /**
         * 打印结果:
         *  读取之前...
         *  读取之后...
         *  18:33:35.565 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [spring-config01.xml]
         *  bean1
         *  bean2
         */
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2(Bean1 bean1) {
            Bean2 bean2 = new Bean2();
            bean2.setBean1(bean1);
            return bean2;
        }
    }

    // 3、较为经典的容器,基于 Java 配置类来创建
    private static void testAnnotationConfigApplicationContext() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Bean2.class).getBean1());

        /**
         * 打印结果:
         *  org.springframework.context.annotation.internalConfigurationAnnotationProcessor
         *  org.springframework.context.annotation.internalAutowiredAnnotationProcessor
         *  org.springframework.context.annotation.internalCommonAnnotationProcessor
         *  org.springframework.context.event.internalEventListenerProcessor
         *  org.springframework.context.event.internalEventListenerFactory
         *  testApplicationContext.Config
         *  bean1
         *  bean2
         *  com.clp.TestApplicationContext$Bean1@670002
         */
    }

    @Configuration
    static class WebConfig {
        /**
         * 产生 Tomcat Web容器(Web服务器) 的工厂
         * @return
         */
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        /**
         * 前控制器 DispatcherServlet
         * @return
         */
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        /**
         * 注册 DispatcherServlet 到 Tomcat 容器(Web服务器)
         * @return
         */
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/"); // 表示所有请求都经过 DispatcherServlet
        }

        /**
         * 创建一个控制器,@Bean内的参数("/hello")表示请求路径,匹配到此路径时会执行该注解下的方法
         * @return
         */
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }

    // 4、较为经典的容器,基于 Java 配置类来创建,用于web环境
    private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        /**
         * 结果:当浏览器输入 127.0.0.1:8080/hello后,接收到 "hello" 返回信息
         */
    }

}

3、Bean的生命周期

3.1、代码演示

以下是Bean生命周期演示的一个例子:

@Slf4j
@Component
public class LifeCircleBean {
    // 以下方法的调用时机顺序:从上到下

    public LifeCircleBean() {
        log.info("构造 LifeCircleBean()");
    }

    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String home) {
        log.info("依赖注入:{}", home);
    }

    @PostConstruct
    public void init() {
        log.info("初始化");
    }

    @PreDestroy
    public void destroy() {
        log.info("销毁");
    }
}

@SpringBootApplication
public class Test03Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Test03Application.class, args);
        context.close();
    }
}

结果:
...
2023-04-10 19:00:46.292  INFO 21796 --- [           main] com.clp.test03.LifeCircleBean            : 构造 LifeCircleBean()
2023-04-10 19:00:46.295  INFO 21796 --- [           main] com.clp.test03.LifeCircleBean            : 依赖注入:D:\jdks\jdk1.8
2023-04-10 19:00:46.296  INFO 21796 --- [           main] com.clp.test03.LifeCircleBean            : 初始化
2023-04-10 19:00:46.438  INFO 21796 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [static/index.html]
2023-04-10 19:00:46.511  INFO 21796 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-04-10 19:00:46.519  INFO 21796 --- [           main] com.clp.test03.Test03Application         : Started Test03Application in 1.58 seconds (JVM running for 2.037)
2023-04-10 19:00:46.551  INFO 21796 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2023-04-10 19:00:46.556  INFO 21796 --- [           main] com.clp.test03.LifeCircleBean            : 销毁

Process finished with exit code 0

第二个例子:

@Slf4j
@Component
public class LifeCircleBean {
    // 以下方法的调用时机顺序:从上到下

    public LifeCircleBean() {
        log.info("构造 LifeCircleBean()");
    }

    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String home) {
        log.info("依赖注入:{}", home);
    }

    @PostConstruct
    public void init() {
        log.info("初始化");
    }

    @PreDestroy
    public void destroy() {
        log.info("销毁");
    }
}

@Slf4j
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("lifeCircleBean")) {
            log.info("<<<<<<<< 实例化之前执行,这里返回的对象会替换掉原本的 bean");
        }
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCircleBean")) {
            log.info("<<<<<<<< 实例化之后执行,这里如果返回 false 会跳过依赖注入阶段");
//            return false;
        }
        return true; // 返回true会继续依赖注入阶段,返回false则会跳过该阶段,一般不会改为false
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCircleBean")) {
            log.info("<<<<<<<< 依赖注入阶段执行,如 @Autowired、@Value、@Resource");
        }
        return pvs;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCircleBean")) {
            log.info("<<<<<<<< 初始化之前执行,这里返回的对象会替换掉原本的 Bean,如 @PostConstruct、@ConfigurationProperties");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCircleBean")) {
            log.info("<<<<<<<< 初始化之后执行,这里返回的对象会替换掉原本的 Bean,如 代理增强");
        }
        return bean;
    }

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCircleBean")) {
            log.info("<<<<<<<< 销毁之前执行,如 @PreDestroy");
        }
    }
}

@SpringBootApplication
public class Test03Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Test03Application.class, args);
        context.close();
    }
}

结果:
...
2023-04-10 19:29:52.201  INFO 4528 --- [           main] com.clp.test03.MyBeanPostProcessor       : <<<<<<<< 实例化之前执行,这里返回的对象会替换掉原本的 bean
2023-04-10 19:29:52.203  INFO 4528 --- [           main] com.clp.test03.LifeCircleBean            : 构造 LifeCircleBean()
2023-04-10 19:29:52.205  INFO 4528 --- [           main] com.clp.test03.MyBeanPostProcessor       : <<<<<<<< 实例化之后执行,这里如果返回 false 会跳过依赖注入阶段
2023-04-10 19:29:52.205  INFO 4528 --- [           main] com.clp.test03.MyBeanPostProcessor       : <<<<<<<< 依赖注入阶段执行,如 @Autowired、@Value、@Resource
2023-04-10 19:29:52.207  INFO 4528 --- [           main] com.clp.test03.LifeCircleBean            : 依赖注入:D:\jdks\jdk1.8
2023-04-10 19:29:52.209  INFO 4528 --- [           main] com.clp.test03.MyBeanPostProcessor       : <<<<<<<< 初始化之前执行,这里返回的对象会替换掉原本的 Bean,如 @PostConstruct、@ConfigurationProperties
2023-04-10 19:29:52.209  INFO 4528 --- [           main] com.clp.test03.LifeCircleBean            : 初始化
2023-04-10 19:29:52.209  INFO 4528 --- [           main] com.clp.test03.MyBeanPostProcessor       : <<<<<<<< 初始化之后执行,这里返回的对象会替换掉原本的 Bean,如 代理增强
2023-04-10 19:29:52.373  INFO 4528 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [static/index.html]
2023-04-10 19:29:52.450  INFO 4528 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-04-10 19:29:52.458  INFO 4528 --- [           main] com.clp.test03.Test03Application         : Started Test03Application in 1.582 seconds (JVM running for 2.075)
2023-04-10 19:29:52.487  INFO 4528 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2023-04-10 19:29:52.494  INFO 4528 --- [           main] com.clp.test03.MyBeanPostProcessor       : <<<<<<<< 销毁之前执行,如 @PreDestroy
2023-04-10 19:29:52.494  INFO 4528 --- [           main] com.clp.test03.LifeCircleBean            : 销毁

Process finished with exit code 0

3.2、设计模式——模板方法

代码演示自定义Bean工厂以及自定义后处理器:

public class TestMethodTemplate {
    public static void main(String[] args) {
        MyBeanFactory beanFactory = new MyBeanFactory();
        beanFactory.addBeanPostProcessor(obj -> System.out.println("解析 @Autowired ..."));
        beanFactory.addBeanPostProcessor(obj -> System.out.println("解析 @Resource ..."));
        Object bean = beanFactory.getBean();
    }

    // 模板方法 Template Method Pattern
    static class MyBeanFactory {
        private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

        public void addBeanPostProcessor(BeanPostProcessor processor) {
            beanPostProcessors.add(processor);
        }

        public Object getBean() {
            Object bean = new Object();
            System.out.println("构造 " + bean);
            System.out.println("依赖注入 " + bean); // 如要实现 @Autowired、@Resource 注解功能要修改代码
            // ... 后处理器对依赖注入阶段作拓展
            for (BeanPostProcessor processor : beanPostProcessors) {
                processor.inject(bean);
            }
            System.out.println("初始化 " + bean);
            return bean;
        }
    }

    // 自定义后处理器
    static interface BeanPostProcessor {
        public void inject(Object obj); // 对依赖注入阶段的功能做一些扩展
    }
}

结果:
构造 java.lang.Object@79fc0f2f
依赖注入 java.lang.Object@79fc0f2f
解析 @Autowired ...
解析 @Resource ...
初始化 java.lang.Object@79fc0f2f

4、Bean后处理器

4.1、常用的Bean后处理器 & 代码演示

Bean后处理器的作用:为Bean的生命周期的各个阶段提供扩展。

首先创建如下3个Bean:

@Slf4j
public class Bean1 {
    private Bean2 bean2;
    private Bean3 bean3;
    private String home;

    @Autowired
    public void setBean2(Bean2 bean2) {
        log.info("@Autowired 生效:{}", bean2);
        this.bean2 = bean2;
    }

    @Resource
    public void setBean3(Bean3 bean3) {
        log.info("@Resource 生效:{}", bean3);
        this.bean3 = bean3;
    }

    @Autowired
    public void setHome(@Value("${JAVA_HOME}") String home) {
        log.info("@Value 生效:{}", home);
        this.home = home;
    }

    @PostConstruct
    public void init() {
        log.info("@PostConstruct 生效");
    }

    @PreDestroy
    public void destroy() {
        log.info("@PreDestroy 生效");
    }

    @Override
    public String toString() {
        return "Bean1{" +
                "bean2=" + bean2 +
                ", bean3=" + bean3 +
                ", home='" + home + '\'' +
                '}';
    }
}

public class Bean2 {
}

public class Bean3 {
}

在主方法中编写如下代码:

public class Test04Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();

        // 用原始方法注册3个bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        // 销毁容器
        context.close();
    }
}

结果:
19:56:42.453 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@75a1cd57
19:56:42.510 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
19:56:42.541 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
19:56:42.541 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
19:56:42.604 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@75a1cd57, started on Mon Apr 10 19:56:42 CST 2023

我们发现 GenericApplicationContext 因为没有添加对应的注解后处理器,因此Bean1的所有注解都没有生效。我们尝试在初始化容器之前往 context 中添加一些后处理器的 Bean:

public class Test04Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();

        // 用原始方法注册3个bean
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);

        // 添加后处理器bean
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 解决@Autowired注解的方法参数有@Value情况
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class); // @Autowired 注解后处理器
        context.registerBean(CommonAnnotationBeanPostProcessor.class); // 不仅会解析 @Resource,还会解析 @PostConstruct 和 @PreDestroy

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        // 销毁容器
        context.close();
    }
}

结果:
20:04:58.619 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@6f2b958e
20:04:58.655 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor'
20:04:58.678 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.CommonAnnotationBeanPostProcessor'
20:04:58.688 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
20:04:58.804 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
20:04:58.805 [main] INFO com.clp.test04.Bean1 - @Resource 生效:com.clp.test04.Bean3@e874448
20:04:58.814 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
20:04:58.831 [main] INFO com.clp.test04.Bean1 - @Value 生效:D:\jdks\jdk1.8
20:04:58.837 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
20:04:58.838 [main] INFO com.clp.test04.Bean1 - @Autowired 生效:com.clp.test04.Bean2@1fc2b765
20:04:58.838 [main] INFO com.clp.test04.Bean1 - @PostConstruct 生效
20:04:58.853 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@6f2b958e, started on Mon Apr 10 20:04:58 CST 2023
20:04:58.854 [main] INFO com.clp.test04.Bean1 - @PreDestroy 生效

Process finished with exit code 0

发现添加了注解后处理器后,在Bean1中定义的注解都生效了。下面演示 @ConfigurationProperties 的bean后处理器:

/**
 * 下面这两个是java自带的环境变量,不用自己配置即可使用
 *      java.home
 *      java.version
 */
@ConfigurationProperties(prefix = "java") // 表示在 java.* 中查找匹配同名字段的属性并赋值
public class Bean4 {
    private String home;
    private String version;

    public String getHome() {
        return home;
    }

    public void setHome(String home) {
        this.home = home;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    @Override
    public String toString() {
        return "Bean4{" +
                "home='" + home + '\'' +
                ", version='" + version + '\'' +
                '}';
    }
}

public class Test04Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();

        // 用原始方法注册3个bean
        context.registerBean("bean4", Bean4.class);

        // 添加后处理器bean
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory()); // 解析 @ConfigurationProperties

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        System.out.println(context.getBean(Bean4.class));

        // 销毁容器
        context.close();
    }
}

结果:
...
Bean4{home='D:\jdks\jdk1.8\jre', version='1.8.0_301'}
...

4.2、@Autowired bean后处理器执行分析

代码演示1:

public class TestAutoWired {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("bean2", new Bean2()); // 这里是直接往bean工厂中添加成品的bean
        beanFactory.registerSingleton("bean3", new Bean3());
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 支持解析 @Value

        // 1、查找哪些属性、方法添加了 @Autowired,这称之为 InjectionMetaData
        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        processor.setBeanFactory(beanFactory);

        Bean1 bean1 = new Bean1();
        System.out.println(bean1);
        processor.postProcessProperties(null, bean1, "bean1"); // 执行依赖注入,解析 @Autowired 包括 @Value
        System.out.println(bean1);
    }
}

结果:
Bean1{bean2=null, bean3=null, home='null'}
11:21:53.821 [main] INFO com.clp.test04.Bean1 - @Value 生效:${JAVA_HOME}
11:21:53.831 [main] INFO com.clp.test04.Bean1 - @Autowired 生效:com.clp.test04.Bean2@4cf777e8
Bean1{bean2=com.clp.test04.Bean2@4cf777e8, bean3=null, home='${JAVA_HOME}'}

代码演示2:

@Slf4j
public class Bean1 {
    private Bean2 bean2;
    @Autowired
    private Bean3 bean3;
    private String home;

    @Autowired
    public void setBean2(Bean2 bean2) {
        log.info("@Autowired 生效:{}", bean2);
        this.bean2 = bean2;
    }

    @Resource
    public void setBean3(Bean3 bean3) {
        log.info("@Resource 生效:{}", bean3);
        this.bean3 = bean3;
    }

    @Autowired
    public void setHome(@Value("${JAVA_HOME}") String home) {
        log.info("@Value 生效:{}", home);
        this.home = home;
    }

    @PostConstruct
    public void init() {
        log.info("@PostConstruct 生效");
    }

    @PreDestroy
    public void destroy() {
        log.info("@PreDestroy 生效");
    }

    @Override
    public String toString() {
        return "Bean1{" +
                "bean2=" + bean2 +
                ", bean3=" + bean3 +
                ", home='" + home + '\'' +
                '}';
    }
}

public class Bean2 {
}

public class Bean3 {
}

public class TestAutoWired {
    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("bean2", new Bean2()); // 这里是直接往bean工厂中添加成品的bean
        beanFactory.registerSingleton("bean3", new Bean3());
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 支持解析 @Value
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器

        // 查找哪些属性、方法添加了 @Autowired,这称之为 InjectionMetaData
        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        processor.setBeanFactory(beanFactory); // 设置bean工厂,供processor使用
        Bean1 bean1 = new Bean1();
        // 后处理器处理 @Autowired @Value
//        processor.postProcessProperties(null, bean1, "bean1");

        // 1.1、下面是模拟 processor.postProcessProperties(null, bean1, "bean1") 的内部执行过程:
        // 调用 processor 的 私有方法 : private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> beanClass, PropertyValues pvs)
        // 该方法的功能:找到 BeanFactory 中哪些 Bean 中的哪些方法被 @Autowired 修饰,收集到 InjectionMetadata 中
        Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod(
                "findAutowiringMetadata", String.class, Class.class, PropertyValues.class
        );
        findAutowiringMetadata.setAccessible(true);
        // 获取 Bean1 上加了 @Autowired 信息的成员变量、方法参数信息
        InjectionMetadata injectionMetadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);
        System.out.println(injectionMetadata); // org.springframework.beans.factory.annotation.InjectionMetadata@4883b407
        // 1.2、调用 injectionMetadata.inject() 方法来进行依赖注入,注入时按类型查找值
//        injectionMetadata.inject(bean1, "bean1", null);
        // 下面是模拟 injectionMetadata.inject(bean1, "bean1", null); 进行依赖注入的过程
        // 1.2.1、-------- 字段上加 @Autowired 的注入
        // 如何按类型查找值
        Field bean3Field = Bean1.class.getDeclaredField("bean3");
        DependencyDescriptor dd1 = new DependencyDescriptor(bean3Field, false);
        Object obj = beanFactory.doResolveDependency(dd1, null, null, null);
        System.out.println(obj); // com.clp.test04.Bean3@31a5c39e
        // 找到之后,通过 bean3Field.set() 进行赋值
        System.out.println(bean1); // Bean1{bean2=null, bean3=null, home='null'}
        bean3Field.setAccessible(true); //
        bean3Field.set(bean1, obj);
        System.out.println(bean1); // Bean1{bean2=null, bean3=com.clp.test04.Bean3@31a5c39e, home='null'}
        // 1.2.2、-------- 方法上加 @Autowired 的注入
        Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
        DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true); // 表示 setBean2 方法的第 0 个参数
        Object obj2 = beanFactory.doResolveDependency(dd2, null, null, null);
        System.out.println(obj2); // com.clp.test04.Bean2@490ab905
        System.out.println(bean1); // Bean1{bean2=null, bean3=com.clp.test04.Bean3@31a5c39e, home='null'}
        setBean2.setAccessible(true);
        setBean2.invoke(bean1, obj2);
        System.out.println(bean1); // Bean1{bean2=com.clp.test04.Bean2@72d818d1, bean3=com.clp.test04.Bean3@490ab905, home='null'}
        // 1.2.3、-------- 方法上加 @Autowired ,并且方法参数加 @Value 的注入
        Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
        DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);
        Object obj3 = beanFactory.doResolveDependency(dd3, null, null, null);
        System.out.println(obj3); // D:\jdks\jdk1.8
    }
}

结果:
org.springframework.beans.factory.annotation.InjectionMetadata@1794d431
com.clp.test04.Bean3@490ab905
Bean1{bean2=null, bean3=null, home='null'}
Bean1{bean2=null, bean3=com.clp.test04.Bean3@490ab905, home='null'}
com.clp.test04.Bean2@72d818d1
Bean1{bean2=null, bean3=com.clp.test04.Bean3@490ab905, home='null'}
13:49:46.853 [main] INFO com.clp.test04.Bean1 - @Autowired 生效:com.clp.test04.Bean2@72d818d1
Bean1{bean2=com.clp.test04.Bean2@72d818d1, bean3=com.clp.test04.Bean3@490ab905, home='null'}
13:49:46.859 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
D:\jdks\jdk1.8

5、BeanFactory后处理器

5.1、代码演示

BeanFactory后处理器的作用:为BeanFactory提供扩展。

先创建如下代码:

// 在test05.component 包下:
@Component
public class Bean2 {
}

// 在test05包下:
public class Bean1 {
}

/**
 * 一共5个bean:
 *  component包中的 Bean2 是一个Bean
 *  Config 自己是一个 Bean
 *  Config 类下的 3 个 @Bean
 */
@Configuration
@ComponentScan("com.clp.test05.component")
public class Config {

    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean(initMethod = "init")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }
}

预期一共创建了5个Bean,我们编写下面代码查看运行结果:

@Slf4j
public class Test05Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);

        // 初始化容器
        context.refresh();  // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 销毁容器
        context.close();
    }
}

结果:
config

发现只打印了config这个bean,也就是说@Bean、@ComponentScan的注解并没有生效。这时我们需要引入BeanFactory后处理器来帮我们对这些注解进行解析。

代码演示:

@Slf4j
public class Test05Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class); // 添加配置类后处理器,处理@ComponentScan、@Bean、@Import、@ImportResource

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 销毁容器
        context.close();
    }
}

结果:
config
org.springframework.context.annotation.ConfigurationClassPostProcessor
bean2
bean1
dataSource
sqlSessionFactoryBean

添加两个Mapper接口:

// test05.mapper 包下
@Mapper
public interface Mapper1 {
}

public interface Mapper2 {
}

代码演示3:

@Slf4j
public class Test05Application {
    public static void main(String[] args) {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class); // 添加配置类后处理器,处理@ComponentScan、@Bean、@Import、@ImportResource
        context.registerBean(MapperScannerConfigurer.class, beanDefinition -> {
            // 添加 Mapper 的扫描的类所在的包路径
            beanDefinition.getPropertyValues().add("basePackage", "com.clp.test05.mapper");
        }); // 相当于 @MapperScanner 的作用

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 销毁容器
        context.close();
    }
}

结果:
...
config
org.springframework.context.annotation.ConfigurationClassPostProcessor
org.mybatis.spring.mapper.MapperScannerConfigurer
bean2
bean1
dataSource
sqlSessionFactoryBean
mapper1
mapper2
...

5.2、自定义BeanFactory后处理器实现

实现@CompoentScan、@Component注解的Bean工厂后处理器代码演示:

// test05.component 包下
@Component
public class Bean3 {
}

// test05.component 包下
@Component
public class Bean2 {
}

// test05 包下
public class Bean1 {
}

// test05 包下
@Configuration
@ComponentScan("com.clp.test05.component")
public class Config {

    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean(initMethod = "init")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }
}

// test05 包下
/**
 * 解析我们编写的 Config类的 @ComponetScan 的 BeanFactory后处理器实现
 */
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
    /**
     * 在 context 调用 refresh() 时会回调这个方法
     * @param configurableListableBeanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

        try {
            // 利用 AnnotationUtils 工具类判断 Config.class 类是否有 @ComponentScan 注解,如果有就返回它,没有返回null
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                // 获取注解上的 basePackages() 信息并遍历
                for (String basePackage : componentScan.basePackages()) {
                    System.out.println(basePackage); // com.clp.test05.component
                    // 将 com.clp.test05.component 转换为 classpath*:com/clp/test05/component/**/*.class
                    String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
                    System.out.println(path); // classpath*:com/clp/test05/component/**/*.class

//                    // 获取 path下 对应的所有资源(使用ApplicationContext的ResourcePatternResolver接口功能)
//                    Resource[] resources = context.getResources(path);
                    // 这里无法获取 ApplicationContext,使用下面的方法获取资源
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);

                    // 创建 MetadataReader 工厂,用来产生 MetadataReader
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    // BeanNameGenerator 用来生成 Bean 的 name
                    BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        System.out.println(resource);
                        // file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean2.class]
                        // file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean3.class]
                        // file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean4.class]
                        // 工厂产生 resource 资源的对应 MetadataReader
                        MetadataReader reader = factory.getMetadataReader(resource);
                        ClassMetadata classMetadata = reader.getClassMetadata();
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        // 查看对应的信息
                        System.out.println("类名:" + classMetadata.getClassName());
                        System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                        System.out.println("是否加了 @Component的派生注解(如@Controller):" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));

                        if (annotationMetadata.hasAnnotation(Component.class.getName())
                                || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            // 构建 Bean 定义
                            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();

                            // 判断 父BeanFactory 是否是 子BeanFactory
                            if (configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
                                DefaultListableBeanFactory beanFactory = ((DefaultListableBeanFactory) configurableListableBeanFactory);
                                // 生成 Bean 的名称
                                String beanName = beanNameGenerator.generateBeanName(beanDefinition, beanFactory);
                                // 将 Bean 定义注册到 Bean 工厂
                                beanFactory.registerBeanDefinition(beanName, beanDefinition);
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// test05 包下
@Slf4j
public class Test05Application {
    public static void main(String[] args) throws IOException {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(ComponentScanPostProcessor.class); // 注册我们自己定义的BeanFactory后处理器

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 销毁容器
        context.close();
    }
}

结果:
com.clp.test05.component
classpath*:com/clp/test05/component/**/*.class
file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean2.class]
类名:com.clp.test05.component.Bean2
是否加了 @Component:true
是否加了 @Component的派生注解(如@Controller):false
file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean3.class]
类名:com.clp.test05.component.Bean3
是否加了 @Component:false
是否加了 @Component的派生注解(如@Controller):true
file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean4.class]
类名:com.clp.test05.component.Bean4
是否加了 @Component:false
是否加了 @Component的派生注解(如@Controller):false
15:10:56.918 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
15:10:56.919 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
15:10:56.919 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
config
com.clp.test05.ComponentScanPostProcessor
bean2
bean3
15:10:56.955 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@156643d4, started on Tue Apr 11 15:10:56 CST 2023

Process finished with exit code 0

在上面的基础上,实现@Bean的Bean工厂后处理器代码演示:

/**
 * 解析 @ComponetScan 的 BeanFactory后处理器实现
 */
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
    /**
     * 在 context 调用 refresh() 时会回调这个方法
     * @param configurableListableBeanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

        try {
            // 利用 AnnotationUtils 工具类判断 Config.class 类是否有 @ComponentScan 注解,如果有就返回它,没有返回null
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                // 获取注解上的 basePackages() 信息并遍历
                for (String basePackage : componentScan.basePackages()) {
                    System.out.println(basePackage); // com.clp.test05.component
                    // 将 com.clp.test05.component 转换为 classpath*:com/clp/test05/component/**/*.class
                    String path = "classpath*:" + basePackage.replace(".", "/") + "/**/*.class";
                    System.out.println(path); // classpath*:com/clp/test05/component/**/*.class

//                    // 获取 path下 对应的所有资源(使用ApplicationContext的ResourcePatternResolver接口功能)
//                    Resource[] resources = context.getResources(path);
                    // 这里无法获取 ApplicationContext,使用下面的方法获取资源
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);

                    // 创建 MetadataReader 工厂,用来产生 MetadataReader
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    // BeanNameGenerator 用来生成 Bean 的 name
                    BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        System.out.println(resource);
                        // file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean2.class]
                        // file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean3.class]
                        // file [G:\Study\Java\java-study\spring-source-study\target\classes\com\clp\test05\component\Bean4.class]
                        // 工厂产生 resource 资源的对应 MetadataReader
                        MetadataReader reader = factory.getMetadataReader(resource);
                        ClassMetadata classMetadata = reader.getClassMetadata();
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        // 查看对应的信息
                        System.out.println("类名:" + classMetadata.getClassName());
                        System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                        System.out.println("是否加了 @Component的派生注解(如@Controller):" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));

                        if (annotationMetadata.hasAnnotation(Component.class.getName())
                                || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            // 构建 Bean 定义
                            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();

                            // 判断 父BeanFactory 是否是 子BeanFactory
                            if (configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
                                DefaultListableBeanFactory beanFactory = ((DefaultListableBeanFactory) configurableListableBeanFactory);
                                // 生成 Bean 的名称
                                String beanName = beanNameGenerator.generateBeanName(beanDefinition, beanFactory);
                                // 将 Bean 定义注册到 Bean 工厂
                                beanFactory.registerBeanDefinition(beanName, beanDefinition);
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@Slf4j
public class Test05Application {
    public static void main(String[] args) throws IOException {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(AtBeanPostProcessor.class); // 添加 BeanFactory 后处理器

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // 销毁容器
        context.close();
    }
}

结果:
com.clp.test05.Config.bean1()
com.clp.test05.Config.bean2()
com.clp.test05.Config.dataSource()
com.clp.test05.Config.sqlSessionFactoryBean(javax.sql.DataSource)
...
config
bean1
bean2
dataSource
sqlSessionFactoryBean
...

Spring将MyBatis的Mapper实现类对象加入到容器中的内部如下:

@Configuration
@ComponentScan("com.clp.test05.component")
public class Config {

    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }

    @Bean(initMethod = "init")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    /**
     * Spring 内部实现注入 ByBatis Mapper 对象的方式(即不通过扫描 @Mapper 注解方式):
     */
//    @Bean
//    public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory) {
//        MapperFactoryBean<Mapper1> factoryBean = new MapperFactoryBean<>(Mapper1.class);
//        factoryBean.setSqlSessionFactory(sqlSessionFactory);
//        return factoryBean;
//    }
//
//    @Bean
//    public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory) {
//        MapperFactoryBean<Mapper2> factoryBean = new MapperFactoryBean<>(Mapper2.class);
//        factoryBean.setSqlSessionFactory(sqlSessionFactory);
//        return factoryBean;
//    }
}

我们自定义BeanFactory后处理来简化这一过程:

public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        try {
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:com/clp/test05/mapper/**/*.class");
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            for (Resource resource : resources) {
                MetadataReader reader = factory.getMetadataReader(resource);
                ClassMetadata classMetadata = reader.getClassMetadata(); // 获取类的元数据
                // 判断该类是否是接口,只处理接口
                if (classMetadata.isInterface()) {
                    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                            .addConstructorArgValue(classMetadata.getClassName())
                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) // 设置自动装配模式
                            .getBeanDefinition();
                    // 将 BeanDefinition 注册到 Bean工厂
                    // 这里新生成了一个BeanDefinition,仅仅是为了生成一个不同的名字
                    AbstractBeanDefinition tempBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                    String beanName = generator.generateBeanName(tempBeanDefinition, registry);
                    registry.registerBeanDefinition(beanName, beanDefinition);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

@Slf4j
public class Test05Application {
    public static void main(String[] args) throws IOException {
        // GenericApplicationContext 是一个 【干净】 的容器(没有额外的内置bean以及后处理器)
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(AtBeanPostProcessor.class); // 添加 BeanFactory 后处理器处理 @Bean 注解
        context.registerBean(MapperPostProcessor.class); // 解析 Mapper 接口

        // 初始化容器
        context.refresh(); // 执行beanFactory后处理器,添加bean后处理器,初始化所有单例

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name + " - " + context.getBean(name));
        }

        // 销毁容器
        context.close();
    }
}

结果:
com.clp.test05.Config.bean1()
com.clp.test05.Config.bean2()
com.clp.test05.Config.dataSource()
com.clp.test05.Config.sqlSessionFactoryBean(javax.sql.DataSource)
...
config - com.clp.test05.Config@65fb9ffc
com.clp.test05.AtBeanPostProcessor - com.clp.test05.AtBeanPostProcessor@3e694b3f
com.clp.test05.MapperPostProcessor - com.clp.test05.MapperPostProcessor@1bb5a082
mapper1 - org.apache.ibatis.binding.MapperProxy@639c2c1d
mapper2 - org.apache.ibatis.binding.MapperProxy@443118b0
bean1 - com.clp.test05.Bean1@765d7657
bean2 - com.clp.test05.component.Bean2@74235045
dataSource - {
	CreateTime:"2023-04-11 16:26:05",
	ActiveCount:0,
	PoolingCount:0,
	CreateCount:0,
	DestroyCount:0,
	CloseCount:0,
	ConnectCount:0,
	Connections:[
	]
}
sqlSessionFactoryBean - org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@618b19ad

6、Aware接口 & InitializingBean接口

Aware 和 InitializingBean 接口:

  • Aware接口提供了一种【内置】的注入手段,可以注入BeanFactory、ApplicationContext。
  • InitializingBean接口提供了一种【内置】的初始化手段。
  • 内置的注入和初始化不受扩展功能的影响,总会被执行,因此Spring框架的内部的类常用它们。

Aware 接口用于注入一些与容器相关的信息,例如:

  • BeanNameAware 注入 Bean 的名字
  • BeanFactoryAware 注入 BeanFactory 容器
  • ApplicationContextAware 注入 ApplicationContext 容器
  • EmbeddedValueResolverAware ${}

为什么不用@Autowired实现后面3个功能?

  • @Autowired的解析需要用到Bean后处理器,属于扩展功能;
  • 而Aware接口属于内置功能,不加任何扩展,Spring就能识别。

某些情况下,扩展功能会失效,而内置功能不会失效。

例1:你会发现用 Aware 注入 ApplicationContext 成功,而 @AutoWired 注入 ApplicationContext 失败(我自己尝试了一下,却发现是可以注入的...)。

代码演示:

/**
 * 调用顺序是从上到下,实现的接口执行顺序是从左到右
 */
@Slf4j
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {

    @Autowired
    public void autowiredApplicationContext(ApplicationContext applicationContext) {
        log.info("当前的Bean " + this + " 基于 @Autowired 注入的容器是:" + applicationContext);
    }

    @Override
    public void setBeanName(String name) {
        log.info("当前的Bean " + this + " 名字叫:" + name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("当前的Bean " + this + " 基于实现 ApplicationContextAware 获取的容器是:" + applicationContext);
    }

    @PostConstruct
    public void init() {
        log.info("当前的Bean " + this + " 基于 @PostConstruct 初始化");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("当前的Bean " + this + " 基于实现 InitializingBean 初始化");
    }
}

@Slf4j
public class Test06Application {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myBean", MyBean.class);
        // 这里不加任何Bean后处理器扩展,导致 @Autowired、@PostConstruct 失效,但是基于实现接口依然生效

        // 初始化容器
        context.refresh();

        // 关闭
        context.close();
    }
}

结果:
16:59:00.464 [main] INFO com.clp.test06.MyBean - 当前的Bean com.clp.test06.MyBean@57fffcd7 名字叫:myBean
16:59:00.467 [main] INFO com.clp.test06.MyBean - 当前的Bean com.clp.test06.MyBean@57fffcd7 基于实现 ApplicationContextAware 获取的容器是:org.springframework.context.support.GenericApplicationContext@156643d4, started on Tue Apr 11 16:59:00 CST 2023
16:59:00.467 [main] INFO com.clp.test06.MyBean - 当前的Bean com.clp.test06.MyBean@57fffcd7 基于实现 InitializingBean 初始化

例2:Java 配置类在添加了 Bean 工厂后处理器后,你会发现用传统接口方式的注入和初始化依然生效,但是@Autowired 和 @PostConstruct 的注入和初始化失效。

代码演示1 - 失效情况:

@Slf4j
@Configuration
public class MyConfig1 {
    @Autowired
    public void setApplicationContext(ApplicationContext context) {
        log.info("注入 ApplicationContext");
    }

    @PostConstruct
    public void init() {
        log.info("初始化");
    }

    /**
     * 添加 BeanFactory 后处理器
     */
    @Bean
    public BeanFactoryPostProcessor processor1() {
        return beanFactory -> log.info("执行 processor1");
    }

}

@Slf4j
public class Test06Application {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
//        context.registerBean("myBean", MyBean.class);
        // 这里不加任何Bean后处理器扩展,导致 @Autowired、@PostConstruct 失效,但是基于实现接口依然生效
        context.registerBean("myConfig1", MyConfig1.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);

        // 初始化容器
        context.refresh();

        /**
         * context.refresh()内部的执行顺序:
         *  1、BeanFactory后处理器 补充 BeanDefinition
         *  2、注册 Bean 后处理器
         *  3、初始化单例
         *  4、依赖注入扩展(如 @Value、@Autowired) 以及 初始化扩展(如 @PostConstruct),会回调2中的Bean后处理器
         *  5、执行 Aware 和 InitializingBean
         *  6、创建成功
         */

        // Java 配置类包含 BeanFactoryPostProcessor的情况,因此要创建其中的BeanFactoryPostProcessor必须提前创建Java配置类,
        // 而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效

        // 关闭
        context.close();
    }
}

结果:
...
17:24:07.347 [main] INFO com.clp.test06.MyConfig1 - 执行 processor1
...

代码演示2 - 问题解决:

@Slf4j
@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("注入 ApplicationContext");
    }

    /**
     * 添加 BeanFactory 后处理器
     */
    @Bean
    public BeanFactoryPostProcessor processor2() {
        return beanFactory -> log.info("执行 processor2");
    }
}

@Slf4j
public class Test06Application {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
//        context.registerBean("myBean", MyBean.class);
        // 这里不加任何Bean后处理器扩展,导致 @Autowired、@PostConstruct 失效,但是基于实现接口依然生效
        context.registerBean("myConfig2", MyConfig2.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);

        // 初始化容器
        context.refresh();

        // 关闭
        context.close();
    }
}

结果:
...
17:25:08.833 [main] INFO com.clp.test06.MyConfig2 - 注入 ApplicationContext
17:25:08.834 [main] INFO com.clp.test06.MyConfig2 - 初始化
...
17:25:08.850 [main] INFO com.clp.test06.MyConfig2 - 执行 processor2

7、初始化与销毁

代码演示:

/**
 * 初始化方法执行顺序:从上到下
 */
@Slf4j
public class Bean1 implements InitializingBean, BeanFactoryAware, ApplicationContextAware {

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("注入 BeanFactory");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("注入 ApplicationContext");
    }

    @PostConstruct
    public void init1() {
        log.info("初始化1");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("初始化2");
    }

    private void init3() {
        log.info("初始化3");
    }
}

@Slf4j
public class Bean2 implements DisposableBean {

    @PreDestroy
    public void destroy1() {
        log.info("销毁1");
    }

    @Override
    public void destroy() throws Exception {
        log.info("销毁2");
    }

    private void destroy3() {
        log.info("销毁3");
    }

}

@SpringBootApplication
public class Test07Application {
    
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Test07Application.class, args);

        context.close();
    }

    @Bean(initMethod = "init3")
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean(destroyMethod = "destroy3")
    public Bean2 bean2() {
        return new Bean2();
    }
    
}

结果:
2023-04-11 17:38:09.087  INFO 41328 --- [           main] com.clp.test07.Bean1                     : 注入 BeanFactory
2023-04-11 17:38:09.088  INFO 41328 --- [           main] com.clp.test07.Bean1                     : 注入 ApplicationContext
2023-04-11 17:38:09.089  INFO 41880 --- [           main] com.clp.test07.Bean1                     : 初始化1
2023-04-11 17:38:09.090  INFO 41880 --- [           main] com.clp.test07.Bean1                     : 初始化2
2023-04-11 17:38:09.090  INFO 41880 --- [           main] com.clp.test07.Bean1                     : 初始化3
...
2023-04-11 17:38:09.366  INFO 41880 --- [           main] com.clp.test07.Bean2                     : 销毁1
2023-04-11 17:38:09.367  INFO 41880 --- [           main] com.clp.test07.Bean2                     : 销毁2
2023-04-11 17:38:09.367  INFO 41880 --- [           main] com.clp.test07.Bean2                     : 销毁3

8、Scope

8.1、代码演示

代码演示:

@Slf4j
@Scope("request")
@Component
public class BeanForRequest {

    @PreDestroy
    public void destroy() {
        log.info("destroy");
    }

}

@Slf4j
@Scope("session")
@Component
public class BeanForSession {

    @PreDestroy
    public void destroy() {
        log.info("destroy");
    }

}

@Slf4j
@Scope("application")
@Component
public class BeanForApplication {

    @PreDestroy
    public void destroy() {
        log.info("destroy");
    }

}

@RestController
public class MyController {

    @Lazy
    @Autowired
    private BeanForRequest beanForRequest;

    @Lazy
    @Autowired
    private BeanForSession beanForSession;

    @Lazy
    @Autowired
    private BeanForApplication beanForApplication;

    @GetMapping(value = "/test", produces = "text/html")
    public String test(HttpServletRequest request, HttpSession session) {
        ServletContext sc = request.getServletContext();
        String str =
                "<ul>" +
                    "<li>" + "request scope: " + beanForRequest + "</li>" +
                    "<li>" + "session scope: " + beanForSession + "</li>" +
                    "<li>" + "application scope: " + beanForApplication + "</li>" +
                "</ul>";
        return str;
    }

}

/**
 * singleton、prototype、request、session、application
 *      jdk >= 9 ,如果反射调用 jdk 中方法,会报 IllegalAccessException
 *          解决:运行时添加参数:--add-opens java.base/java.lang=ALL-UNNAMED
 *      jdk <= 8 ,不会有这个问题
 */
@SpringBootApplication
public class Test08Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Test08Application.class);
    }
}

在火狐浏览器访问:localhost:8080/test
    request scope: com.clp.test08.BeanForRequest@5fc14f91
    session scope: com.clp.test08.BeanForSession@75e2f23a
    application scope: com.clp.test08.BeanForApplication@736c9214
每次刷新页面,request scope 一行的 BeanForRequest 的地址都会发生改变,session行 和 application行 不会

在谷歌浏览器访问:localhost:8080/test
    request scope: com.clp.test08.BeanForRequest@41bb6af1
    session scope: com.clp.test08.BeanForSession@8660ca
    application scope: com.clp.test08.BeanForApplication@736c9214
每次刷新页面,request scope 一行的 BeanForRequest 的地址都会发生改变,session行 和 application行 不会

根据演示结果可以发现,同一个浏览器不断刷新页面,request 域的 BeanForRequest 对象都不一样,session域 和 application域 的对象都不变;不同浏览器的 request

域 和 session域 不一样,但 application 域是一样的。

在 application.properties 中设置session超时时间:

# 设置session的失效时间
server.servlet.session.timeout=10s

日志打印如下:

...
2023-04-12 11:03:27.679  INFO 35420 --- [alina-utility-2] com.clp.test08.BeanForSession            : destroy
...

说明存放在Session域的BeanForSession对象被销毁了。

8.2、Scope 失效问题

代码演示:

@Scope("prototype")
@Component
public class F1 {
}

/**
 * 默认为单例
 */
@Component
public class E {

    @Autowired
    private F1 f1;

    public F1 getF1() {
        return f1;
    }
}

@Slf4j
@ComponentScan("com.clp.test08")
public class Test08Application2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test08Application2.class);

        E e = context.getBean(E.class);
        log.info("{}", e.getF1());
        log.info("{}", e.getF1());
        log.info("{}", e.getF1());

        context.close();
    }
}

结果:
...
11:13:18.869 [main] INFO com.clp.test08.Test08Application2 - com.clp.test08.F1@339bf286
11:13:18.870 [main] INFO com.clp.test08.Test08Application2 - com.clp.test08.F1@339bf286
11:13:18.870 [main] INFO com.clp.test08.Test08Application2 - com.clp.test08.F1@339bf286
...

我们期望e每次获取到的F1都是不一样的,但是打印的结果都是同一个F1,也就是F1的@Scope失效了。

原因:对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的F1,因此E用的始终是第一次依赖注入的F1。

解决:

  • 仍然使用@Lazy生成代理;
  • 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的F1对象。

代码演示 - 解决:

@Scope("prototype")
@Component
public class F1 {
}

/**
 * 解决方式2:在@Scope添加proxyMode属性
 */
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}

@Scope("prototype")
@Component
public class F3 {
}

@Scope("prototype")
@Component
public class F4 {
}

/**
 * 默认为单例
 */
@Component
public class E {

    /**
     * 解决方式 1:添加 @Lazy 注解
     */
    @Lazy
    @Autowired
    private F1 f1;

    @Autowired
    private F2 f2;

    /**
     * 解决方式3:注入 F3 的对象工厂,在获取 F3 使通过 f3Factory 获取 F3 对象返回
     */
    @Autowired
    private ObjectFactory<F3> f3Factory;

    /**
     * 解决方式3:注入 applicationContext 容器,通过 getBean() 方法获取多例
     */
    @Autowired
    private ApplicationContext applicationContext;

    public F1 getF1() {
        return f1;
    }

    public F2 getF2() {
        return f2;
    }

    public F3 getF3() {
        return f3Factory.getObject();
    }

    public F4 getF4() {
        return applicationContext.getBean(F4.class);
    }

}

@Slf4j
@ComponentScan("com.clp.test08")
public class Test08Application2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test08Application2.class);

        E e = context.getBean(E.class);

        // 解决方式1(@Lazy):E 始终使用同一个 F1代理类,但每次调用 getF1() 方法 代理类代理内部都会有一个不同的 F1 对象
        log.info("{}, {}", e.getF1().getClass(), e.getF1());
        log.info("{}, {}", e.getF1().getClass(), e.getF1());
        log.info("{}, {}", e.getF1().getClass(), e.getF1());
        log.info("\n");

        // 解决方式2:@Scope添加proxyMode属性
        log.info("{}, {}", e.getF2().getClass(), e.getF2());
        log.info("{}, {}", e.getF2().getClass(), e.getF2());
        log.info("{}, {}", e.getF2().getClass(), e.getF2());
        log.info("\n");

        // 解决方式3:注入 F3 的对象工厂,在获取 F3 使通过 f3Factory 获取 F3 对象返回
        log.info("{}, {}", e.getF3().getClass(), e.getF3());
        log.info("{}, {}", e.getF3().getClass(), e.getF3());
        log.info("{}, {}", e.getF3().getClass(), e.getF3());
        log.info("\n");

        // 解决方式4:注入 applicationContext 容器,通过 getBean() 方法获取多例
        log.info("{}, {}", e.getF4().getClass(), e.getF4());
        log.info("{}, {}", e.getF4().getClass(), e.getF4());
        log.info("{}, {}", e.getF4().getClass(), e.getF4());
        log.info("\n");

        context.close();
    }
}

结果:
...
11:39:23.792 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F1$$EnhancerBySpringCGLIB$$27c62a72, com.clp.test08.F1@1bc715b8
11:39:23.796 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F1$$EnhancerBySpringCGLIB$$27c62a72, com.clp.test08.F1@1c55f277
11:39:23.796 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F1$$EnhancerBySpringCGLIB$$27c62a72, com.clp.test08.F1@3e8f7922
11:39:23.796 [main] INFO com.clp.test08.Test08Application2 - 

11:39:23.796 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F2$$EnhancerBySpringCGLIB$$761f5b9, com.clp.test08.F2@58e6d4b8
11:39:23.797 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F2$$EnhancerBySpringCGLIB$$761f5b9, com.clp.test08.F2@1de5f0ef
11:39:23.797 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F2$$EnhancerBySpringCGLIB$$761f5b9, com.clp.test08.F2@376a312c
11:39:23.797 [main] INFO com.clp.test08.Test08Application2 - 

11:39:23.798 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F3, com.clp.test08.F3@5ef0d29e
11:39:23.798 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F3, com.clp.test08.F3@3ce3db41
11:39:23.798 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F3, com.clp.test08.F3@e260766
11:39:23.798 [main] INFO com.clp.test08.Test08Application2 - 

11:39:23.800 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F4, com.clp.test08.F4@34a97744
11:39:23.800 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F4, com.clp.test08.F4@4275c20c
11:39:23.800 [main] INFO com.clp.test08.Test08Application2 - class com.clp.test08.F4, com.clp.test08.F4@7c56e013
11:39:23.800 [main] INFO com.clp.test08.Test08Application2 - 
...

9、AOP

9.1、AOP实现之 ajc 编译器

使用ajc编译器实现代理增强。不常用。

@Slf4j
@Aspect
public class MyAspect {

    @Before("execution(* com.clp.test09.service.MyService.*())")
    public void before() {
        log.info("before()");
    }

}

@Slf4j
@Service
public class MyService {

    public final void foo() {
        log.info("foo()");
        bar();
    }

    public void bar() {
        log.info("bar()");
    }

}

@Slf4j
@SpringBootApplication
public class Test09Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Test09Application.class, args);

        MyService service = context.getBean(MyService.class);
        log.info("service class: {}", service.getClass());
        service.foo();

        context.close();
    }
}

9.2、AOP 实现之 agent 类加载

在类加载阶段进行增强。

注意几点:
    1、版本选择了 Java 8,因为目前的aspectj-maven-plugin 1.14.0 最高只支持 Java 16
    2、运行时需要在 VM options 里加入 javaagent:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar
        把其中 C:/Users/manyh/.m2/repository 改为你自己的 maven 仓库起始地址

代码同9.1。

9.3、AOP 实现之 proxy —— jdk 动态代理

9.3.1、JDK 动态代理实现

/**
 * jdk 动态代理:只能针对接口进行代理,cglib没有这个限制
 *      注意的几点:
 *          1、Target 和 Proxy 是兄弟关系(都实现了Foo接口)
 *          2、Target 可以是 final 的
 */
public class JdkProxyTest {

    interface Foo {
        void foo();
    }

    static class Target implements Foo {
        @Override
        public void foo() {
            System.out.println("target foo");
        }
    }

    public static void main(String[] args) {
        // 准备目标对象
        Target target = new Target();

        ClassLoader loader = JdkProxyTest.class.getClassLoader(); // 用来加载在运行期间动态生成的字节码
        Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before");
                // 反射调用
                return method.invoke(target, args); // 让代理也返回方法执行结果
            }
        });
        proxy.foo();

    }

}

结果:
before
target foo

9.3.2、jdk 动态代理实现原理

/**
 * jdk 动态代理实现原理(模拟实现)
 */
public class JdkProxyPrinciple {

    interface Foo {
        void foo();
        int bar();
    }

    static class Target implements Foo {
        @Override
        public void foo() {
            System.out.println("target foo()");
        }

        @Override
        public int bar() {
            System.out.println("target bar()");
            return 100;
        }
    }

    // 模拟代理类实现
    static class $Proxy0 extends Proxy implements Foo {
        private static Method foo;
        private static Method bar;
        static {
            try {
                foo = Foo.class.getMethod("foo");
                bar = Foo.class.getMethod("bar");
            } catch (NoSuchMethodException e) {
                throw new NoSuchMethodError(e.getMessage());
            }
        }

        public $Proxy0(InvocationHandler h) {
            super(h);
        }

        /**
         * 这里异常抛出分为2类:运行时异常,直接抛出;受检异常,转换成运行时异常再抛出
         */
        @Override
        public void foo() {
            try {
                h.invoke(this, foo, new Object[0]);
            } catch (RuntimeException | Error e) {
                throw e;
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }

        @Override
        public int bar() {
            try {
                Object result = h.invoke(this, bar, new Object[0]);
                return ((int) result);
            } catch (RuntimeException | Error e) {
                throw e;
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }

    }

    public static void main(String[] args) {
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
                // 1、实现功能的增强
                System.out.println("before...");
                // 2、调用目标
                return method.invoke(new Target(), args);
            }
        });
        proxy.foo();
        proxy.bar();
    }
}

结果:
before...
target foo()
before...
target bar()

9.3、AOP 实现之 proxy —— cglib 动态代理

9.3.1、cglib 动态代理实现

/**
 * cglib 动态代理
 *      注意:
 *          1、Target 是父类型, proxy 是子类型
 *          2、Target 不能为 final
 *          3、Target 的方法不能为 final (private方法默认为final),如果为final,不会报错,但是该方法不会被代理
 */
public class CglibProxyTest {

    static class Target {
        public void foo() {
            System.out.println("target foo()");
        }

        public final void finalFoo() {
            System.out.println("target finalFoo()");
        }
    }

    public static void main(String[] args) {
        // 准备目标对象
        Target target = new Target();

        Target proxy = (Target) Enhancer.create(Target.class, new MethodInterceptor() {
            /**
             *
             * @param o 代理对象
             * @param method 方法
             * @param objects 方法参数
             * @param methodProxy
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before ...");

//                Object result = method.invoke(target, objects); // 用方法反射调用目标对象
//                Object result = methodProxy.invoke(target, args); // MethodProxy 可以避免反射调用目标,内部没有用反射,需要目标才能调用(Spring使用的方式)
                Object result = methodProxy.invokeSuper(o, args);// MethodProxy 可以避免反射调用目标,内部没有用反射,不需要目标,需要代理对象自身才能调用

                System.out.println("after ...");
                return result;
            }
        });

        proxy.foo();
        System.out.println("-------------");
        proxy.finalFoo();
    }
}

结果:
before ...
target foo()
after ...
-------------
target finalFoo()

9.3.2、cglib 动态代理实现原理

/**
 * cglib 动态代理实现原理(模拟)
 */
public class CglibProxyPrinciple {

    static class Target {
        public void save() {
            System.out.println("save()");
        }

        public void save(int i) {
            System.out.println("save(int)");
        }

        public void save(long l) {
            System.out.println("save(long)");
        }
    }

    static class Proxy extends Target {
        private static Method save0;
        private static Method save1;
        private static Method save2;
        private static MethodProxy save0Proxy;
        private static MethodProxy save1Proxy;
        private static MethodProxy save2Proxy;
        static {
            try {
                save0 = Target.class.getMethod("save");
                save0 = Target.class.getMethod("save", int.class);
                save0 = Target.class.getMethod("save", long.class);
                save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");
                save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper");
                save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper");
            } catch (NoSuchMethodException e) {
                throw new NoSuchMethodError(e.getMessage());
            }
        }

        private MethodInterceptor interceptor;


        public void setMethodInterceptor(MethodInterceptor interceptor) {
            this.interceptor = interceptor;
        }

        // >>>>>>>>>>>>>>>>>>>>>>>>>>> 带原始功能的方法
        public void saveSuper() {
            super.save();
        }
        public void saveSuper(int i) {
            super.save(i);
        }
        public void saveSuper(long l) {
            super.save(l);
        }

        // >>>>>>>>>>>>>>>>>>>>>>>>>>> 带增强功能的方法
        @Override
        public void save() {
            try {
                interceptor.intercept(this, save0, new Object[0], save0Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }

        @Override
        public void save(int i) {
            try {
                interceptor.intercept(this, save0, new Object[]{i}, save1Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }

        @Override
        public void save(long l) {
            try {
                interceptor.intercept(this, save0, new Object[]{l}, save2Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    }

    public static void main(String[] args) {
        Target target = new Target();

        Proxy proxy = new Proxy();
        proxy.setMethodInterceptor(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("before");
//                return method.invoke(target, args);
//                return methodProxy.invoke(target, args); // 内部没有反射,需要结合目标对象
                return methodProxy.invokeSuper(proxy, args); // 内部没有反射,不需要目标对象,仅需要代理对象自身
            }
        });
        proxy.save();
        proxy.save(1);
        proxy.save(2L);
    }
}

结果:
before
save()
before
save(int)
before
save(long)

9.4、jdk 和 cglib 的统一

/**
 * 两个切面概念:
 *      aspect =
 *          通知1(advice) + 切点1(pointcut)
 *          通知2(advice) + 切点2(pointcut)
 *          通知3(advice) + 切点3(pointcut)
 *      advisor = 更细粒度的切面,包含一个通知和切点
 */
public class Test11Application {

    interface I1 {
        void foo();

        void bar();
    }

    static class Target1 implements I1 {
        @Override
        public void foo() {
            System.out.println("target1 foo");
        }

        @Override
        public void bar() {
            System.out.println("target1 bar");
        }
    }

    static class Target2 {
        public void foo() {
            System.out.println("target2 foo");
        }

        public void bar() {
            System.out.println("target2 bar");
        }
    }

    public static void main(String[] args) {
        // 1、备好切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        // 2、备好通知
        MethodInterceptor advice = invocation -> {
            System.out.println("before...");
            Object result = invocation.proceed(); // 调用目标
            System.out.println("after...");
            return result;
        };
        // 3、备好切面
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
        /**
         * 4、创建代理
         *      a、proxyTargetClass = false 且 目标实现了接口,用 jdk 实现
         *      b、proxyTargetClass = false 且 目标没有实现接口,用 cglib 实现
         *      c、proxyTargetClass = true,总是使用 cglib 实现
         */
        Target1 target1 = new Target1();
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(target1); // 设置目标对象
        factory.addAdvisor(advisor); // 设置切面
        factory.setInterfaces(target1.getClass().getInterfaces());
        factory.setProxyTargetClass(true);
        I1 proxy = ((I1) factory.getProxy());
        System.out.println(proxy.getClass());
        proxy.foo();
        proxy.bar();
    }
}

结果:
class com.clp.test11.Test11Application$Target1$$EnhancerBySpringCGLIB$$8c8f5c2
before...
target1 foo
after...
target1 bar

9.5、切点匹配

代码演示:

public class Test12Application {
    public static void main(String[] args) throws NoSuchMethodException {
        AspectJExpressionPointcut pointcut1 = new AspectJExpressionPointcut();
        pointcut1.setExpression("execution(* bar())");
        System.out.println(pointcut1.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pointcut1.matches(T1.class.getMethod("bar"), T1.class));

        System.out.println("------------------------");

        // 只能处理方法上的注解,不能处理如 T2、T3 那样加在类上的注解(Spring 的@Transactional的实现不是使用这种方式)
        AspectJExpressionPointcut pointcut2 = new AspectJExpressionPointcut();
        pointcut2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");
        System.out.println(pointcut2.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pointcut2.matches(T1.class.getMethod("bar"), T1.class));

        System.out.println("------------------------");

        // 模拟 Spring 实现 @Transactional 的实现
        StaticMethodMatcherPointcut pointcut3 = new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                // 检查方法上是否加了 @Transactional 注解
                MergedAnnotations annotations = MergedAnnotations.from(method);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }
                // 检查类上是否加了 @Transactional 注解(第二个参数是表示会从父类及以上查找注解)
                annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }
                return false;
            }
        };
        System.out.println(pointcut3.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pointcut3.matches(T1.class.getMethod("bar"), T1.class));
        System.out.println(pointcut3.matches(T2.class.getMethod("foo"), T2.class));
        System.out.println(pointcut3.matches(T3.class.getMethod("foo"), T3.class));

    }

    static class T1 {
        @Transactional
        public void foo() {}

        public void bar() {}
    }

    @Transactional
    static class T2 {
        public void foo() {}
    }

    @Transactional
    interface I3 {
        void foo();
    }

    static class T3 implements I3 {
        @Override
        public void foo() {}
    }
}

结果:
false
true
------------------------
true
false
------------------------
true
false
true
true

9.6、从 @Apsect 到 Advisor

9.6.1、AnnotationAwareAspectJAutoProxyCreator Bean后处理器

创建代理的Bean后处理器 AnnotationAwareAspectJAutoProxyCreator 代码演示:

// 修改包路径以访问 Spring 的该包下的类的 protect 方法
package org.springframework.aop.framework.autoproxy;

// import ...

public class Test13Application {

    // 以下2个 Target 并没有交给 Spring容器管理
    static class Target1 {
        public void foo() {
            System.out.println("target1 foo");
        }
    }

    static class Target2 {
        public void bar() {
            System.out.println("target2 bar");
        }
    }

    // 高级的切面类,在 Spring 容器中
    @Aspect
    // 设置切面优先级(数字越小优先级越大),则该切面类下的所有切面优先级都是1,
    // 如果不设置,那么 高级切面类(@Aspect)优先级低于低级切面类(Advisor)
    // 只能设置在类上,设置在方法上没有效果
    @Order(1) 
    static class Aspect1 {
        @Before("execution(* foo())")
        public void before() {
            System.out.println("aspect1 before...");
        }

        @After("execution(* foo())")
        public void after() {
            System.out.println("aspect1 after...");
        }
    }

    // 配置类,在 Spring 容器中
    @Configuration
    static class Config {
        @Bean
        public MethodInterceptor advice3() {
            return invocation -> {
                System.out.println("advice3 before...");
                Object result = invocation.proceed();
                System.out.println("advice3 after...");
                return result;
            };
        }

        // 低级切面
        @Bean
        public Advisor advisor3(MethodInterceptor advice3) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice3);
            advisor.setOrder(2); // 设置优先级(设置为2,则低于上面的 @Aspect)
            return advisor;
        }
    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("aspect1", Aspect1.class);
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class); // 配置类 @Bean 生效

        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class); // 注解感知自动代理创建器 Bean处理器
        // 处理器在Bean创建过程中参与的时机:创建 -> () -> 依赖注入 -> 初始化 -> ()

        context.refresh();

//        for (String name : context.getBeanDefinitionNames()) {
//            System.out.println(name);
//        }

        System.out.println("--------------------------");

        // AnnotationAwareAspectJAutoProxyCreator 中的几个方法演示:
        /**
         *  1、findEligibleAdvisors() 找到【资格】的Advisors
         *      a、有【资格】的 Advisor,一部分是低级的,可以由自己编写,如本例中的 advisor3
         *      b、有【资格】的 Advisor,另一部分是高级的,由解析 @Aspect 后获得
         */
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        List<Advisor> advisors = creator.findEligibleAdvisors(Target1.class, "target1");// 根据目标类来获取切面
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }

        System.out.println("--------------------------");

        /**
         * 2、wrapIfNecessary()
         *      a、它内部调用 findEligibleAdvisors(),只要返回集合不空,则表示需要创建代理
         */
        Object target1Proxy = creator.wrapIfNecessary(new Target1(), "target1", "target1");
        System.out.println(target1Proxy.getClass());
        Object target2Proxy = creator.wrapIfNecessary(new Target2(), "target2", "target2");
        System.out.println(target2Proxy);

        System.out.println("--------------------------");
        ((Target1) target1Proxy).foo();
        System.out.println("--------------------------");
    }
}

结果:
...
--------------------------
class org.springframework.aop.framework.autoproxy.Test13Application$Target1$$EnhancerBySpringCGLIB$$6ce32796
org.springframework.aop.framework.autoproxy.Test13Application$Target2@548e6d58
--------------------------
aspect1 before...
advice3 before...
target1 foo
advice3 after...
aspect1 after...
--------------------------

9.6.2、代理创建时机

代码演示:

/**
 * 代理的创建时机:
 *      1、初始化(@PostConstruct)之后(无循环依赖时)
 *      2、实例创建后,依赖注入前(有循环依赖时),并暂存于二级缓存
 * 依赖注入与初始化不应该被增强,仍应被施加于原始对象
 */
public class Test14Application {

    @Configuration
    static class Config {
        @Bean // 解析 @Aspect,产生代理
        public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
        }

        @Bean // 解析 @Autowired
        public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            return new AutowiredAnnotationBeanPostProcessor();
        }

        @Bean // 解析 @PostConstruct
        public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            return new CommonAnnotationBeanPostProcessor();
        }

        @Bean
        public Advisor advisor(MethodInterceptor advice) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, advice);
        }

        @Bean
        public MethodInterceptor methodInterceptor() {
            return invocation -> {
                System.out.println("advice before...");
                Object result = invocation.proceed();
                System.out.println("advice after...");
                return result;
            };
        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    // Bean1 和 Bean2 有循环依赖关系
    static class Bean1 {
        public Bean1() {
            System.out.println("Bean1()");
        }

        @Autowired
        public void setBean2(Bean2 bean2) {
            System.out.println("Bean1 setBean2(),Bean2 class:" + bean2.getClass());
        }

        @PostConstruct
        public void init() {
            System.out.println("Bean1 init()");
        }

        public void foo() {
            System.out.println("Bean1 foo()");
        }
    }

    static class Bean2 {
        public Bean2() {
            System.out.println("Bean2()");
        }

        @Autowired
        public void setBean1(Bean1 bean1) {
            System.out.println("Bean2 setBean1(),Bean1 class:" + bean1.getClass());
        }

        @PostConstruct
        public void init() {
            System.out.println("Bean2 init()");
        }
    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(Config.class);
        context.refresh();

        System.out.println("---------------");
        context.getBean(Bean1.class).foo();
        System.out.println("---------------");

        context.close();
    }
}

结果:
...
Bean1()
11:08:15.359 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
Bean2()
Bean2 setBean1(),Bean1 class:class com.clp.test14.Test14Application$Bean1$$EnhancerBySpringCGLIB$$5bccda13
Bean2 init()
Bean1 setBean2(),Bean2 class:class com.clp.test14.Test14Application$Bean2
Bean1 init()
---------------
advice before...
Bean1 foo()
advice after...
---------------
...

9.6.3、高级切面转低级切面

代码演示:

public class Test14Application2 {

    static class Aspect {

        @Before("execution(* foo())")
        public void before1() {
            System.out.println("before1");
        }

        @Before("execution(* foo())")
        public void before2() {
            System.out.println("before2");
        }

        public void after() {
            System.out.println("after");
        }

        public void afterReturning() {
            System.out.println("afterReturning");
        }

        public void afterThrowing() {
            System.out.println("afterThrowing");
        }

        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            return null;
        }

    }

    static class Target {
        public void foo() {
            System.out.println("Target foo()");
        }
    }

    /**
     * @Before 前置通知会被转换为下面原始的 AspectJMethodBeforeAdvice 形式,该对象包含了如下信息:
     *      1、通知代码从哪儿来;
     *      2、切点是什么(这里为啥要切点,后面解释);
     *      3、通知对象如何创建,本例公用一个 Aspect 对象
     * 类似的通知还有:
     *      1、AspectJAroundAdvice - 环绕通知;
     *      2、AspectJAfterReturningAdvice;
     *      3、AspectJAfterThrowingAdvice - 环绕通知;
     *      4、AspectJAfterAdvice - 环绕通知。
     * 
     * @param args
     */
    public static void main(String[] args) {
        AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());

        // 高级切面类转低级切面类
        List<Advisor> advisors = new ArrayList<>();
        for (Method method : Aspect.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Before.class)) {
                // 解析切点
                String expression = method.getAnnotation(Before.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                advisors.add(advisor);
            }
        }
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }
    }
}

结果:
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void com.clp.test14.Test14Application2$Aspect.before2()]; aspect name '']
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void com.clp.test14.Test14Application2$Aspect.before1()]; aspect name '']

9.7、静态通知调用

通知会统一转换为环绕通知 MethodInterceptor:

  • 其实无论 ProxyFactory 基于哪种方式创建代理,最后干活(调用 advice) 的是一个 MethodInvocation 对象;
  • MethodInvocation 要知道 Advice 有哪些,还要知道 Target,调用次序如下:advice1_before -> advice2_before -> target -> advice2_after -> advice1_after,将 MethodInvocation 放入当前线程里,在调用链时可以从当前线程获取 MethodInvocation;
  • 从上可以看出,环绕通知才适合作为 Advice,因此其他 before、afterReturning都会被转换为环绕通知;
  • 统一转换为环绕通知,体现的是设计模式中的适配器模式:对外是为了方便使用,要区分 before、afterReturning;对内统一是环绕通知,统一用 MethodInterceptor 表示。

 代码演示:

// 修改包路径以访问 Spring 的该包下的类的 protect 方法
package org.springframework.aop.framework;

// import...

public class Test14Application2 {

    static class Aspect {

        @Before("execution(* foo())")
        public void before1() {
            System.out.println("before1");
        }

        @Before("execution(* foo())")
        public void before2() {
            System.out.println("before2");
        }

//        @After("execution(* foo())")
        public void after() {
            System.out.println("after");
        }

        @AfterReturning("execution(* foo())")
        public void afterReturning() {
            System.out.println("afterReturning");
        }

        @AfterThrowing("execution(* foo())")
        public void afterThrowing() {
            System.out.println("afterThrowing");
        }

        @Around("execution(* foo())")
        public void around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("around_before");
            pjp.proceed();
            System.out.println("around_after");
        }

    }

    static class Target {
        public void foo() {
            System.out.println("Target foo()");
        }
    }

    public static void main(String[] args) throws Throwable {
        AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());

        // 1、高级切面类转低级切面类
        List<Advisor> advisors = new ArrayList<>();
        for (Method method : Aspect.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Before.class)) {
                // 解析切点
                String expression = method.getAnnotation(Before.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                advisors.add(advisor);
            } else if (method.isAnnotationPresent(AfterReturning.class)) {
                // 解析切点
                String expression = method.getAnnotation(AfterReturning.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                advisors.add(advisor);
            } else if (method.isAnnotationPresent(Around.class)) {
                // 解析切点
                String expression = method.getAnnotation(Around.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                advisors.add(advisor);
            }
        }
        System.out.println("----------------------");
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }

        // 2、通知统一转换为环绕通知 MethodInterceptor
        Target target = new Target();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        // 最外层的环绕通知将 MethodInvocation 放入 当前线程中(ThreadLocal)
        proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
        proxyFactory.addAdvisors(advisors);
        System.out.println("----------------------");
        /**
         * 此步获取所有执行时需要的 advice (静态)
         *      1、即统一转换为 MethodInterceptor 环绕通知,这体现在方法名中的 Interceptors 上;
         *      2、适配如下:
         *          - MethodBeforeAdviceAdapter 将 @Before 注解生成的 AspectJMethodBeforeAdvice 适配为 MethodBeforeAdviceInterceptor
         *          - AfterReturningAdviceAdapter 将 @AfterReturning 注解生成的 AspectJAfterReturningAdvice 适配为 AfterReturningAdviceInterceptor
         */
        List<Object> interceptors = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class);
        for (Object interceptor : interceptors) {
            System.out.println(interceptor);
        }

        // 3、创建并执行调用链(所有环绕通知 + 目标)
        System.out.println("----------------------");
        MethodInvocation methodInvocation = new ReflectiveMethodInvocation(
                null, target, Target.class.getMethod("foo"), new Object[0], Target.class, interceptors
        );
        methodInvocation.proceed(); // 嵌套调用
    }
}

结果:
----------------------
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAfterReturningAdvice: advice method [public void org.springframework.aop.framework.Test14Application2$Aspect.afterReturning()]; aspect name '']
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public void org.springframework.aop.framework.Test14Application2$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name '']
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.Test14Application2$Aspect.before1()]; aspect name '']
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.Test14Application2$Aspect.before2()]; aspect name '']
----------------------
org.springframework.aop.interceptor.ExposeInvocationInterceptor@59f99ea
org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor@27efef64
org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public void org.springframework.aop.framework.Test14Application2$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name ''
org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@6f7fd0e6
org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@47c62251
----------------------
around_before
before1
before2
Target foo()
around_after
afterReturning

代码演示 methodInvocation.procceed() 方法的调用过程(责任链模式):

// 3.1、模拟 methodInvocation.proceed(); 的调用过程
/**
 * 该调用过程是一个简单的递归过程:
 *      1、proceed() 方法调用链中下一个环绕通知;
 *      2、每个环绕通知内部继续调用 proceed();
 *      3、调用到没有更多通知了,就调用目标方法
 */
public class Test14Application3 {

    static class Target {
        public void foo() {
            System.out.println("Target foo()");
        }
    }

    static class Advice1 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Advice1.before()");
            Object result = invocation.proceed(); // 调用下一个通知或目标
            System.out.println("Advice1.after()");
            return result;
        }
    }

    static class Advice2 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Advice2.before()");
            Object result = invocation.proceed();// 调用下一个通知或目标
            System.out.println("Advice2.after()");
            return result;
        }
    }

    static class MyInvocation implements MethodInvocation {
        private Object target; // 目标对象
        private Method method; // 目标方法
        private Object[] args; // 目标方法参数
        private List<MethodInterceptor> methodInterceptors;
        private int count = 1; // 调用次数

        public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptors) {
            this.target = target;
            this.method = method;
            this.args = args;
            this.methodInterceptors = methodInterceptors;
        }

        @Override
        public Method getMethod() {
            return method;
        }

        @Override
        public Object[] getArguments() {
            return args;
        }

        @Override
        public Object proceed() throws Throwable {
            if (count > methodInterceptors.size()) {
                // 调用目标,返回并结束递归操作
                return method.invoke(target, args);
            }
            // 逐一调用通知,count + 1
            MethodInterceptor methodInterceptor = methodInterceptors.get(count++ - 1);
            return methodInterceptor.invoke(this);
        }

        @Override
        public Object getThis() {
            return target;
        }

        @Override
        public AccessibleObject getStaticPart() {
            return method;
        }
    }

    public static void main(String[] args) throws Throwable {
        Target target = new Target();
        List<MethodInterceptor> methodInterceptors = Arrays.asList(new Advice1(), new Advice2());
        MyInvocation invocation = new MyInvocation(target, Target.class.getMethod("foo"), new Object[0], methodInterceptors);
        invocation.proceed();
    }
}

结果:
Advice1.before()
Advice2.before()
Target foo()
Advice2.after()
Advice1.after()

9.8、动态通知调用

/**
 * 有参数绑定的通知调用时还需要切点,对参数进行匹配及绑定,复杂程度高,性能比无参数的通知调用低
 */
public class Test15Application {

    @Aspect
    static class MyAspect {
        @Before("execution(* foo(..))") // 静态通知调用,不带参数绑定,执行时不需要切点,生成的是 MethodBeforeAdviceInterceptor
        public void before1() {
            System.out.println("before1");
        }

        @Before("execution(* foo(..)) && args(x)") // 动态通知调用,需要参数绑定,执行时需要切点对象,生成的是 InterceptorAndDynamicMethodMatcher
        public void before2(int x) {
            System.out.printf("before2(%d)%n", x);
        }
    }

    static class Target {
        public void foo(int x) {
            System.out.printf("target foo(%d)%n", x);
        }
    }

    @Configuration
    static class MyConfig {
        @Bean // 解析 @Aspect,将高级切面转为低级切面,并创建代理对象
        public AnnotationAwareAspectJAutoProxyCreator proxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
        }

        @Bean // 自定义高级切面
        public MyAspect myAspect() {
            return new MyAspect();
        }
    }

    public static void main(String[] args) throws NoSuchMethodException {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(MyConfig.class);
        context.refresh();

        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        List<Advisor> advisors = creator.findEligibleAdvisors(Target.class, "target");

        Target target = new Target();
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(target);
        factory.addAdvisors(advisors);
        Object proxy = factory.getProxy();// 获取代理

        List<Object> interceptors = factory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo", int.class), Target.class);
        for (Object interceptor : interceptors) {
            System.out.println(interceptor);
        }
    }
}

结果:
org.springframework.aop.interceptor.ExposeInvocationInterceptor@77f80c04
org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@1dac5ef
org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher@5c90e579

 

posted on 2023-04-12 17:34  啊噢1231  阅读(44)  评论(0编辑  收藏  举报

导航

回到顶部