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
是否加了 @Componenttrue
是否加了 @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
是否加了 @Componentfalse
是否加了 @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
是否加了 @Componentfalse
是否加了 @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 classclass com.clp.test14.Test14Application$Bean1$$EnhancerBySpringCGLIB$$5bccda13
Bean2 init()
Bean1 setBean2()Bean2 classclass 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   啊噢1231  阅读(51)  评论(0编辑  收藏  举报

导航

统计信息

回到顶部
点击右上角即可分享
微信分享提示

1、容器接口
1.1、BeanFactory功能
1.1.1、什么是 BeanFactory ?
1.1.2、BeanFactory能干点啥?
1.2、ApplicationContext功能
1.2.1、父接口 - MessageSource
1.2.2、父接口 - ResourcePatternResolver & EnvironmentCapable
1.2.3、父接口 - EnvironmentCapable
1.2.4、父接口 - ApplicationEventPublisher
2、容器实现
2.1、BeanFactory 实现
2.2、ApplicationContext 实现
3、Bean的生命周期
3.1、代码演示
3.2、设计模式——模板方法
4、Bean后处理器
4.1、常用的Bean后处理器 & 代码演示
4.2、@Autowired bean后处理器执行分析
5、BeanFactory后处理器
5.1、代码演示
5.2、自定义BeanFactory后处理器实现
6、Aware接口 & InitializingBean接口
7、初始化与销毁
8、Scope
8.1、代码演示
8.2、Scope 失效问题
9、AOP
9.1、AOP实现之 ajc 编译器
9.2、AOP 实现之 agent 类加载
9.3、AOP 实现之 proxy —— jdk 动态代理
9.3.1、JDK 动态代理实现
9.3.2、jdk 动态代理实现原理
9.3、AOP 实现之 proxy —— cglib 动态代理
9.3.1、cglib 动态代理实现
9.3.2、cglib 动态代理实现原理
9.4、jdk 和 cglib 的统一
9.5、切点匹配
9.6、从 @Apsect 到 Advisor
9.6.1、AnnotationAwareAspectJAutoProxyCreator Bean后处理器
9.6.2、代理创建时机
9.6.3、高级切面转低级切面
9.7、静态通知调用
9.8、动态通知调用