后置处理器
在Spring框架中,后置处理器(Post-Processor)是一种常用的扩展机制,可以让开发者在Spring容器实例化Bean对象前后,对Bean对象进行自定义的处理。后置处理器是Spring框架中非常重要的一种机制,它可以在Bean对象实例化、初始化、销毁等过程中,介入Bean对象的生命周期,从而实现对Bean对象的定制化管理。
Spring框架中提供了很多后置处理器接口,比如BeanPostProcessor、InstantiationAwareBeanPostProcessor等等,开发者可以根据自己的需求实现这些接口,以实现自定义的Bean对象处理逻辑。例如,BeanPostProcessor接口中定义了两个方法:postProcessBeforeInitialization和postProcessAfterInitialization,可以让开发者在Bean对象实例化后,初始化前和初始化后,对Bean对象进行自定义处理。
后置处理器在Spring框架中应用广泛,常用于实现Bean对象的自动注入、AOP、事务管理等功能,可以大大简化开发者的工作。同时,后置处理器也是Spring框架的重要组成部分,对于深入理解Spring框架的工作原理和机制,也是必须了解的内容。
@PostConstruct注解
在Spring Boot中,@PostConstruct注解用于标记一个方法,该方法会在Bean对象创建后,且依赖注入完成后调用。它的作用类似于JavaEE中的@PostConstruct注解,用于在Bean对象初始化时执行一些初始化操作,例如数据加载、资源初始化等等。
具体来说,@PostConstruct注解的作用如下:
- 初始化Bean对象:@PostConstruct注解可以用于标记一个方法,在Bean对象创建后自动调用该方法,从而完成Bean对象的初始化工作。
- 注入依赖:@PostConstruct注解的方法会在依赖注入完成后调用,可以在该方法中访问依赖对象,完成一些需要依赖注入的操作。
- 简化初始化操作:使用@PostConstruct注解可以将Bean对象的初始化操作集中到一个方法中,使得代码更加简洁、可读性更高,并且避免了在构造函数中进行初始化操作的风险。
需要注意的是,@PostConstruct注解只能用于标记一个非静态、无参、并且返回void的方法,否则Spring容器将会抛出异常。此外,如果一个Bean对象中存在多个使用@PostConstruct注解标记的方法,那么它们的执行顺序是不确定的,因此不应该依赖于它们的执行顺序。如果需要有序执行多个初始化方法,可以使用@Order注解或者实现Ordered接口来指定执行顺序。
classpath*
classpath*:是Java中用于指定类路径的通配符,可以在指定类路径时匹配多个路径。在classpath*:路径中,classpath表示类路径,而*表示通配符,可以匹配多个路径。
在Java中,类路径是指Java虚拟机用于查找类和资源的路径。类路径可以包含多个目录和JAR文件,其中包含了Java应用程序需要的类和资源文件。classpath*则是一种特殊的类路径格式,它可以用于指定包含多个目录或JAR文件的类路径,从而在Java应用程序中查找类和资源文件时可以更加灵活。
在Spring框架中,classpath*:常常被用于指定Bean定义的扫描路径,从而自动扫描指定路径下的所有类并将其注册为Bean对象。通过使用classpath*,可以避免指定具体的文件名或路径,从而更加灵活地管理Bean对象。例如,可以使用如下代码指定Bean扫描路径:
@Configuration @ComponentScan(basePackages = {"com.example.app"}, includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {MyBean.class}), excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {MyExcludeBean.class})) public class AppConfig { // ... }
在上面的代码中,@ComponentScan注解使用了classpath*:指定Bean扫描路径为com.example.app,同时还包含了一个包含过滤器和一个排除过滤器。其中,包含过滤器指定只扫描MyBean类,排除过滤器指定不扫描MyExcludeBean类。通过这种方式,可以精确控制Bean扫描范围,从而实现更加灵活的配置管理。
@Bean(initMethod = "init")
@Bean(initMethod = "init")中的initMethod是一个可选的属性,它指定了一个在Bean初始化完成后需要被调用的初始化方法的名称。这个方法必须没有参数,返回类型可以是任意类型,如果有任何异常抛出,Spring容器将捕获并记录它们,但不会重新抛出。
当一个bean被创建时,Spring容器会首先创建一个实例对象,然后填充所有的属性值,最后调用初始化方法来完成一些其他的初始化工作。如果你不指定initMethod属性,Spring容器会默认调用Java类中的无参构造方法作为初始化方法。
以下是一个示例:
@Component public class MyBean { public void init() { // 在这里执行bean的初始化工作 } }
在这个例子中,MyBean类中定义了一个名为init()的初始化方法,这个方法会在MyBean对象被创建完成后被自动调用。如果你使用了@Bean(initMethod = "init")注解来声明MyBean对象的创建,Spring容器会在MyBean对象被创建完成后调用init()方法来完成一些其他的初始化工作。
refresh()方法
在 Spring 容器启动时,会调用 refresh() 方法来加载所有的 Bean 定义,并创建 Bean 实例。在应用程序运行期间,如果需要动态更新 Bean 定义或者刷新容器状态,可以再次调用 refresh() 方法。
refresh() 方法的主要执行过程包括以下几个步骤:
- 创建 BeanFactory,加载 Bean 定义;
- 对 Bean 定义进行解析和验证;
- 注册 BeanPostProcessor;
- 实例化非懒加载的单例 Bean,并执行 BeanPostProcessor 的前置和后置处理方法;
- 实例化懒加载的单例 Bean,并执行 BeanPostProcessor 的前置和后置处理方法;
- 发布容器事件;
- 启动容器中的所有定时任务。
总的来说,refresh() 方法是 Spring 容器启动和初始化的核心方法,它确保所有的 Bean 定义都被正确加载,并创建了相应的 Bean 实例。
@Lazy
Spring 中的 @Lazy 注解可以用来控制 Bean 的创建时机。默认情况下,Spring 容器会在启动时就实例化所有的单例(Singleton)Bean,即所谓的“饥饿实例化”。如果我们的应用中存在很多单例 Bean,这样的做法可能会导致启动时间变慢。
使用 @Lazy 注解,可以将 Bean 的创建时机推迟到第一次使用时。当一个 Bean 被标记了 @Lazy 注解后,它会在第一次被使用时才被创建,而不是在 Spring 容器启动时立即创建。这种方式称为“懒加载”。
@Lazy 注解可用于类、字段和方法上。当用于类上时,表示将该类声明为懒加载 Bean;当用于字段上时,表示该字段是一个懒加载的依赖项;当用于方法上时,表示该方法返回的对象是一个懒加载 Bean。
使用 @Lazy 注解可以有效地减少启动时间和资源消耗,尤其是对于那些占用大量资源或者需要较长时间初始化的 Bean。但需要注意的是,懒加载可能会导致在第一次使用时出现较长的等待时间,因为 Bean 的初始化和依赖注入可能需要较长时间,还有如果懒加载的 Bean 在容器中被多个线程同时访问,可能会导致线程安全问题,需要进行相应的处理。