首页 > 其他分享 >Spring高级

Spring高级

时间:2023-04-12 17:44:40浏览次数:39  
标签:Spring 高级 class Bean context com public clp

1、容器接口

1.1、BeanFactory功能

1.1.1、什么是 BeanFactory ?

BeanFactory:

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

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

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

public interface BeanFactory {
    // ...

    Object getBean(String var1) throws BeansException;

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

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

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

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

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

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

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

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

        System.out.println(caContext);
    }

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

1.1.2、BeanFactory能干点啥?

回到BeanFactory接口的定义:

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

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

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

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

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

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

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

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

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

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

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

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

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

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

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

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

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

@Slf4j
@Component
public class Component1 {
}

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

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

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

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

}

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

1.2、ApplicationContext功能

我们查看ApplicationContext类图:

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

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

1.2.1、父接口 - MessageSource

其中MessageSource接口定义如下:

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

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

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

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

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

code_hello=hello

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

code_hello="你好"

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

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

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

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

}

结果:
"你好"

1.2.2、父接口 - ResourcePatternResolver & EnvironmentCapable

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

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

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

        ApplicationContext aContext = caContext;

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

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

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

1.2.3、父接口 - EnvironmentCapable

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

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

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

        ApplicationContext aContext = caContext;

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

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

1.2.4、父接口 - ApplicationEventPublisher

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

代码演示1:

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

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

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

        ApplicationContext aContext = caContext;

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

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

代码演示2:

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

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

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

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

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

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

        ApplicationContext aContext = caContext;

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

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

2、容器实现

2.1、BeanFactory 实现

先看以下代码演示:

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

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

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

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

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

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

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

结果:
config

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

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

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

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

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

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

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

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

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

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

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

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

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

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

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

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

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

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

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

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

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

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

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

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

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

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

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

总结:

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

2.2、ApplicationContext 实现

@Slf4j
public class TestApplicationContext {

    @Slf4j
    static class Bean1 {
    }

    @Slf4j
    static class Bean2 {
        private Bean1 bean1;

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

        public Bean1 getBean1() {
            return bean1;
        }
    }

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

    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

3、Bean的生命周期

3.1、代码演示

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

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

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

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

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

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

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

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

Process finished with exit code 0

第二个例子:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Process finished with exit code 0

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

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

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

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

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

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

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

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

4、Bean后处理器

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

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

首先创建如下3个Bean:

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

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

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

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

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

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

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

public class Bean2 {
}

public class Bean3 {
}

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

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

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

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

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

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

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

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

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

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

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

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

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

Process finished with exit code 0

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

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

    public String getHome() {
        return home;
    }

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

    public String getVersion() {
        return version;
    }

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

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

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

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

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

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

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

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

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

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

代码演示1:

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

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

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

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

代码演示2:

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

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

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

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

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

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

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

public class Bean2 {
}

public class Bean3 {
}

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

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

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

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

5、BeanFactory后处理器

5.1、代码演示

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

先创建如下代码:

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

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

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

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

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

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

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

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

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

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

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

结果:
config

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

代码演示:

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

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

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

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

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

添加两个Mapper接口:

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

public interface Mapper2 {
}

代码演示3:

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

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

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

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

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

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

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

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

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

// test05 包下
public class Bean1 {
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Process finished with exit code 0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    }
}

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

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

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

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

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

6、Aware接口 & InitializingBean接口

Aware 和 InitializingBean 接口:

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

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

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

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

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

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

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

代码演示:

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

    @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);
    }

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

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

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

@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 的统一

 

 

 

 

 

P46

 

 

 

P17

 

标签:Spring,高级,class,Bean,context,com,public,clp
From: https://www.cnblogs.com/aoe1231/p/17297007.html

相关文章

  • springboot filter 和 interceptor 使用
    userholderpublicclassUserHolder{privatestaticThreadLocal<String>userThreadLocal=newThreadLocal<>();//为当前的线程变量赋值上用户信息publicstaticvoidsetLoginUser(Stringuser){userThreadLocal.set(user);}//从当前......
  • SpringBoot启动后获取特定注解的Bean实例代码(转)
    来自:https://zhuanlan.zhihu.com/p/375973197本文研究的主要是Spring启动后获取所有拥有特定注解的Bean,具体如下。最近项目中遇到一个业务场景,就是在Spring容器启动后获取所有的Bean中实现了一个特定接口的对象,第一个想到的是ApplicationContextAware,在setApplicationContext中......
  • springboot中获取指定包下的包含某个注解的全部类(转)
    来自:https://www.cnblogs.com/lexiaoyao1995/p/13943784.html需求获取spring项目里的带有某个注解的全部类难点需要扫描指定包路径下的类,同时也要扫描其下所有子包思路可以自己实现,推荐使用spring的工具类代码packagecom.example.demo;importcom.example.demo.annos......
  • spring声明式事务(注解)
     xml中开启注解驱动:  ......
  • Springboot LIST进行分割方法
    在开发使用中我们经常会需要把一个LIST按组进行分割,下面记录一下我的使用方法以便以后使用/***LIST进行分割*@paramlist*@paramsubNum*@param<T>*@return*/publicstatic<T>List<List<T>>splistList(List<T>list,int......
  • 21-springcloud-feign-3-使用Feign实现消费者
    使用Feign实现消费者,我们通过下面步骤进行: 第一步:创建普通SpringBoot工程把接口放在通用的接口层、常量类、model的项目中第二步:添加依赖要添加的依赖主要是spring-cloud-starter-netflix-eureka-client和spring-cloud-starter-feign,如下:<!--spring-cloud......
  • SPRING ThreadPoolTaskExecutor示例
    0、前言当我们需要实现并发、异步等操作时,通常都会使用到ThreadPoolTaskExecutor。它是springcore包中的,而ThreadPoolExecutor是JDK中的JUC。ThreadPoolTaskExecutor是对ThreadPoolExecutor进行了封装处理。1、示例1.1、配置类importorg.springframework.context.annotation......
  • 22-springcloud-feign-4-使用Feign实现消费者的测试
    负载均衡:我们知道,SpringCloud提供了Ribbon来实现负载均衡,使用Ribbo直接注入一个RestTemplate对象即可,RestTemplate已经做好了负载均衡的配置;在SpringCloud下,使用Feign也是直接可以实现负载均衡的,定义一个有@FeignClient注解的接口,然后使用@RequestMapping注解......
  • SpringMVC 长轮询
    修改web.xml让其支持异步请求<filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param>&l......
  • Springboot集成dubbo完整过程(三)
    准备工作1,准备mysql服务环境2,准备redis服务环境3,准备zookeeper服务环境4,准备逆向生成bean的xml配置文件5,准备slf4j日志xml配置文件6,准备一个sql脚本1,搭建创建服务工程1,创建一个空的父工程,用来统一管理依赖2,创建一个interface接口工程,主要存放业务bean,接口类3,创建一......