Java面试宝典专栏范围:JAVA基础,面向对象编程(OOP),异常处理,集合框架,Java I/O,多线程编程,设计模式,网络编程,框架和工具等全方位面试题详解
每日更新Java面试宝典专栏:Java面试宝典
感兴趣的可以先收藏起来
,大家在遇到JAVA面试题等相关问题都可以给我留言咨询
,希望帮助更多的人
实例化: Spring 容器根据配置文件或注解实例化 Bean 对象。
属性注入: Spring 将依赖(通过构造器、setter 方法或字段注入)注入到 Bean 实例中。
初始化前的扩展机制: 若 Bean 实现了 BeanNameAware 等 aware 接口,则执行 aware 注入。
初始化前(BeanPostProcessor): 在 Bean 初始化之前,可通过 BeanPostProcessor 接口对 Bean 进行额外处理。
初始化: 调用 InitializingBean 接口的 afterPropertiesSet () 方法或通过 init - method 属性指定的初始化方法。
初始化后(BeanPostProcessor): 在 Bean 初始化后,可通过 BeanPostProcessor 进一步处理。
使用 Bean: Bean 初始化完成后,可被容器中的其他 Bean 使用。
销毁: 当容器关闭时,Spring 调用 DisposableBean 接口的 destroy () 方法或通过 destroy - method 属性指定的销毁方法。
Spring 容器在启动过程中,会扫描指定的配置文件(如 XML 配置文件)或带有特定注解(如 @Component
、@Service
、@Repository
、@Controller
等)的类。对于 XML 配置,会根据
标签的定义来创建 Bean 实例;对于注解方式,容器会利用反射机制来实例化对应的类。例如,当容器扫描到一个标注了 @Service
的类时,会创建该类的对象,这个对象就是一个 Bean 实例。
UserService
类依赖 UserRepository
,可以在 UserService
的构造函数中接收 UserRepository
作为参数,Spring 会自动将合适的 UserRepository
实例注入进来。UserService
类有一个 userRepository
属性,提供 setUserRepository
方法,Spring 会调用该方法将 UserRepository
实例设置进去。@Autowired
等注解,Spring 会自动将匹配的依赖对象注入到该字段中。不过字段注入可能会导致一些测试和依赖管理上的问题,因为它使得依赖关系不够明确。当 Bean 实现了 BeanNameAware
接口时,Spring 容器会在 Bean 实例化之后,在其他初始化操作之前,将当前 Bean 在配置文件或注解中定义的名称注入到 Bean 中。通过实现该接口的 setBeanName
方法,Bean 可以获取自身的名称。类似的,还有 BeanFactoryAware
接口,实现它可以让 Bean 获取到当前的 BeanFactory
实例,从而可以在 Bean 内部对容器进行一些操作,比如获取其他 Bean 等。
BeanPostProcessor
是 Spring 提供的一个强大的扩展接口。开发者可以自定义实现该接口的类,在其中实现 postProcessBeforeInitialization
方法。当容器创建每个 Bean 实例并完成属性注入后,在调用 Bean 的初始化方法之前,会先调用所有注册的 BeanPostProcessor
的 postProcessBeforeInitialization
方法,开发者可以在这个方法中对 Bean 进行一些额外的处理,比如修改 Bean 的属性值、动态代理增强等操作。
InitializingBean
接口时,在 Bean 的属性注入完成之后,Spring 会调用该接口的 afterPropertiesSet
方法。可以在这个方法中编写一些初始化逻辑,比如对一些资源的初始化操作、建立数据库连接等。
标签指定 init - method
属性,其值为 Bean 类中定义的一个无参方法名。Spring 会在属性注入完成后,调用这个指定的方法进行初始化操作。同样,在使用注解配置时,也可以通过 @Bean
注解的 initMethod
属性来指定类似的初始化方法。BeanPostProcessor
的 postProcessAfterInitialization
方法会在 Bean 的初始化方法调用完成之后被调用。在这里可以对已经初始化好的 Bean 进行进一步的处理,比如再次进行动态代理增强、添加一些额外的功能逻辑等。一些框架整合时,会利用这个时机来对 Bean 进行增强以实现特定的功能,比如 AOP 代理的创建等。
当一个 Bean 完成了上述所有的生命周期步骤,就可以被容器中的其他 Bean 依赖和使用了。其他 Bean 可以通过属性注入等方式获取到这个 Bean 的实例,然后调用其提供的方法来完成业务逻辑。例如,OrderService
依赖 UserService
,UserService
已经完成初始化,OrderService
可以通过构造器注入获取到 UserService
实例,进而调用 UserService
中的方法来处理订单相关业务中涉及用户的操作。
DisposableBean
接口时,在 Spring 容器关闭时,会调用该接口的 destroy
方法。可以在这个方法中编写一些资源释放的逻辑,比如关闭数据库连接、释放文件句柄等。
标签指定 destroy - method
属性,其值为 Bean 类中定义的一个无参方法名。Spring 容器关闭时,会调用这个指定的方法来进行资源清理等销毁操作。在注解配置中,也可以通过 @Bean
注解的 destroyMethod
属性来指定销毁方法。Spring Bean 的生命周期还与其作用域密切相关:
在一个 Web 应用中,经常需要与数据库进行交互。我们可以创建一个DatabaseConnection
的 Bean。
DatabaseConnection
对象,并注入数据库连接所需的配置信息,比如数据库地址、用户名、密码等。InitializingBean
接口,在afterPropertiesSet
方法中编写代码来建立实际的数据库连接,比如使用 JDBC 驱动来获取一个数据库连接对象。UserRepository
,可以通过属性注入获取DatabaseConnection
实例,然后利用这个连接来执行 SQL 语句,查询、插入、更新或删除数据。DisposableBean
接口,在destroy
方法中关闭数据库连接,释放相关资源,避免资源泄漏。很多应用都需要记录日志来跟踪程序运行情况。我们可以创建一个LoggerBean
。
LoggerBean
实例,并注入日志相关的配置,例如日志级别、日志文件路径等。LoggerBean
中可以实现InitializingBean
接口或者通过init - method
指定一个初始化方法。在这个方法里,根据注入的配置信息来初始化日志记录器,比如设置日志输出格式,加载日志配置文件等。OrderService
,可以注入LoggerBean
,在业务方法中调用LoggerBean
的方法来记录日志,例如在处理订单时记录订单创建时间、订单状态变更等信息。LoggerBean
的销毁方法(如果实现了DisposableBean
接口或者配置了destroy - method
)可以执行一些清理工作,比如关闭日志文件等。在分布式系统中,经常会使用消息队列来进行异步通信。假设有一个MessageProducer
的 Bean 用于向消息队列发送消息。
MessageProducer
,并注入消息队列的连接信息,如消息队列服务器地址、端口等,以及一些生产者相关的配置,比如消息持久化策略等。InitializingBean
接口,在afterPropertiesSet
方法中建立与消息队列服务器的连接,创建消息生产者对象,并进行一些必要的配置初始化。ProductService
,当有新商品发布等事件发生时,可以注入MessageProducer
,调用其方法将相关消息发送到消息队列中,以便其他系统或组件进行处理。MessageProducer
的销毁方法可以关闭与消息队列的连接,释放资源,确保系统正常退出。下面将通过多种方式来展示在 Spring 中自定义 Bean 生命周期的具体 Java 代码示例,包含使用接口、注解以及 XML 配置等方式。
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
// 使用 @Component 注解将该类注册为 Spring Bean
@Component
public class MyBeanUsingInterfaces implements InitializingBean, DisposableBean {
// 实现 InitializingBean 接口的 afterPropertiesSet 方法,用于初始化操作
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("MyBeanUsingInterfaces: Initializing...");
}
// 实现 DisposableBean 接口的 destroy 方法,用于销毁操作
@Override
public void destroy() throws Exception {
System.out.println("MyBeanUsingInterfaces: Destroying...");
}
}
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;
// 使用 @Component 注解将该类注册为 Spring Bean
@Component
public class MyBeanUsingAnnotations {
// 使用 @PostConstruct 注解,在 Bean 属性注入完成后执行初始化操作
@PostConstruct
public void init() {
System.out.println("MyBeanUsingAnnotations: Initializing...");
}
// 使用 @PreDestroy 注解,在 Spring 容器关闭时执行销毁操作
@PreDestroy
public void destroy() {
System.out.println("MyBeanUsingAnnotations: Destroying...");
}
}
首先创建一个 Java 类:
public class MyBeanUsingXml {
// 初始化方法
public void init() {
System.out.println("MyBeanUsingXml: Initializing...");
}
// 销毁方法
public void destroy() {
System.out.println("MyBeanUsingXml: Destroying...");
}
}
然后在 applicationContext.xml 中进行配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBeanUsingXml" class="com.example.MyBeanUsingXml"
init-method="init" destroy-method="destroy"/>
beans>
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
// 使用 @Component 注解将该类注册为 Spring Bean
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
// 在 Bean 初始化前执行的方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Before Initialization: " + beanName);
return bean;
}
// 在 Bean 初始化后执行的方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("After Initialization: " + beanName);
return bean;
}
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 对于使用注解的方式
AnnotationConfigApplicationContext annotationContext = new AnnotationConfigApplicationContext();
annotationContext.scan("com.example");
annotationContext.refresh();
// 获取并使用 Bean
MyBeanUsingInterfaces myBeanUsingInterfaces = annotationContext.getBean(MyBeanUsingInterfaces.class);
MyBeanUsingAnnotations myBeanUsingAnnotations = annotationContext.getBean(MyBeanUsingAnnotations.class);
// 关闭容器,触发销毁方法
annotationContext.close();
// 对于使用 XML 配置的方式
ClassPathXmlApplicationContext xmlContext = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBeanUsingXml myBeanUsingXml = xmlContext.getBean("myBeanUsingXml", MyBeanUsingXml.class);
xmlContext.close();
}
}
InitializingBean
和 DisposableBean
接口,Spring 会自动调用相应的方法来完成初始化和销毁操作。@PostConstruct
和 @PreDestroy
注解,让代码更简洁,Spring 会在合适的时机调用被注解的方法。init - method
和 destroy - method
,Spring 会根据配置调用对应的方法。