1. Spring Bean生命週期各個階段
首先編寫一個Bean:
@Component
public class LifeCycleBean {
public LifeCycleBean(){
System.out.println("Bean 構造");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}")String javaHome){
System.out.println("Bean 依賴注入:"+javaHome);
}
@PostConstruct
public void init(){
System.out.println("Bean 初始化");
}
@PreDestroy
public void destroy(){
System.out.println("Bean 被銷燬");
}
}
編寫主方法測試程式碼:
@SpringBootApplication
public class A03Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A03Application.class, args);
context.close();
}
}
Bean 構造
Bean 依賴注入:/opt/development_tools/jdk21/jdk-21.0.3
Bean 初始化
2024-06-08T17:06:10.657+08:00 INFO 30992 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 9000 (http) with context path ''
2024-06-08T17:06:10.672+08:00 INFO 30992 --- [ main] com.cherry.a03.A03Application : Started A03Application in 2.645 seconds (process running for 3.334)
Bean 被銷燬
我們發現。完整的Bean生命週期是:
- 透過構造方法例項化Bean物件
- 對Bean物件進行依賴注入(該Bean 可能會引入其它的Bean物件)
- 對Bean物件進行初始化
- Bean物件隨著容器的銷燬而銷燬(當然是在容器銷燬前而銷燬)
由於預設的而BeanFactory對於Bean管理只有核心的功能,而對Bean功能的怎增強則是透過Bean後處理器來完成的,我破門可以使用不同的Bean後處理器針對Bean不同的生命週期進行擴充套件。這裡舉一個簡單的例子:
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean")){
System.out.println("<<<銷燬之前執行 如 @PreDestroy<<<");
}
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean")){
System.out.println("<<<例項化之前執行,這裡返回的物件會替換掉原來的bean <<<");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
System.out.println("<<<例項化之後執行,這裡返回false會跳過依賴注入 <<<");
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean")){
System.out.println("<<<依賴注入階段執行,如@Autowired, @AValue, @Resource <<<");
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean")){
System.out.println("<<<初始化Bean之前執行,這裡返回的物件會替換掉原來的Bean物件,如@POsrConstruct, @ConfigurationProperties <<<");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean")){
System.out.println("<<< 初始化之後執行,這裡返回的物件會替換掉原來的Bean,如代理增強<<<");
}
return bean;
}
}
執行:
<<<例項化之前執行,這裡返回的物件會替換掉原來的bean <<<
Bean 構造
<<<例項化之後執行,這裡返回false會跳過依賴注入 <<<
<<<依賴注入階段執行,如@Autowired, @AValue, @Resource <<<
Bean 依賴注入:/opt/development_tools/jdk21/jdk-21.0.3
<<<初始化Bean之前執行,這裡返回的物件會替換掉原來的Bean物件,如@POsrConstruct, @ConfigurationProperties <<<
Bean 初始化
<<< 初始化之後執行,這裡返回的物件會替換掉原來的Bean,如代理增強<<<
2024-06-08T17:31:34.698+08:00 INFO 31600 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 9000 (http) with context path ''
2024-06-08T17:31:34.713+08:00 INFO 31600 --- [ main] com.cherry.a03.A03Application : Started A03Application in 2.913 seconds (process running for 3.471)
<<<銷燬之前執行 如 @PreDestroy<<<
Bean 被銷燬
2. 模板設計模式
模板設計模式就是在不改變原有程式碼的基礎上,提高現有程式碼的擴充套件能力。
模擬Spring容器編寫一個BeanFactory
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public void inject(Object bean) {
System.out.println("解析 @Autowired");
}
});
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public void inject(Object bean) {
System.out.println("解析 @Resource");
}
});
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public void inject(Object bean) {
System.out.println("解析 @Value");
}
});
beanFactory.getBean();
}
static class MyBeanFactory{
public Object getBean(){
Object bean = new Object();
System.out.println("構造: "+bean);
System.out.println("依賴注入: "+bean); //@Autowired註解解析
for(BeanPostProcessor processor:processors){
processor.inject(bean);
}
System.out.println("初始化: "+bean);
return bean;
}
// 儲存bean後處理器
private List<BeanPostProcessor> processors = new ArrayList<>();
// 想後處理器集合中新增後處理器
public void addBeanPostProcessor(BeanPostProcessor processor){
processors.add(processor);
}
}
static interface BeanPostProcessor{
public void inject(Object bean); // 對依賴注入階段的功能進行擴充套件
}
}
構造: java.lang.Object@5f184fc6
依賴注入: java.lang.Object@5f184fc6
解析 @Autowired
解析 @Resource
解析 @Value
初始化: java.lang.Object@5f184fc6
Process finished with exit code 0
將不確定的邏輯操作抽象成介面,將來在特定的時機呼叫來呼叫抽象方法。
3. 常見的Bean後處理器
首先定義幾個Bean物件:
Bean1:
public class Bean1 {
private Bean2 bean2;
private Bean3 bean3;
private String home;
@Autowired
public void setBean2(Bean2 bean2){
System.out.println("@Autowired 生效:"+bean2);
this.bean2 = bean2;
}
@Resource
public void setBean3(Bean3 bean3){
System.out.println("@Autowired 生效:"+bean3);
this.bean3 = bean3;
}
@Autowired
public void setHome(@Value("${JAVA_HOME}")String home){
System.out.println("@Value 生效:"+home);
this.home = home;
}
@PostConstruct
public void init(){
System.out.println("@PostConstruct 生效");
}
@PreDestroy
public void destroy(){
System.out.println("@PreDestroy 生效");
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", home='" + home + '\'' +
'}';
}
}
Bean2:
public class Bean2 {}
Bean3:
public class Bean3 {}
Bean4:
/**
*java.home=
* java.version=
*/
@ConfigurationProperties(prefix = "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 + '\'' +
'}';
}
}
主程式:
@SpringBootApplication
public class A04Application {
public static void main(String[] args) {
// GenericApplicationContext是一個比較容器,它並沒有新增額外的bean處理器
GenericApplicationContext context = new GenericApplicationContext();
// 想容器中註冊三個bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4",Bean4.class);
// 新增一個解析@Autowired和@Value註解的後處理器
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// 新增一個協助@Value值獲取的後處理器,一般配合AutowiredAnnotationBeanPostProcessor後處理器使用
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 新增一個解析@Resource,@PostConstruct,@PreDestroy註解的後處理器
context.registerBean(CommonAnnotationBeanPostProcessor.class);
// 新增對@ConfigurationProperties註解解析的後處理器
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
//初始化容器--執行beanFactory後處理器,新增bean後處理器,初始化所有單例
context.refresh();
System.out.println(context.getBean(Bean4.class));
//銷燬容器
context.close();
}
}
執行結果如下:
@Autowired 生效:com.cherry.a04.Bean3@77167fb7
@Autowired 生效:com.cherry.a04.Bean2@2f112965
@Value 生效:/opt/development_tools/jdk21/jdk-21.0.3
@PostConstruct 生效
Bean4{home='/usr/lib/jvm/jdk-21-oracle-x64', version='21.0.3'}
@PreDestroy 生效
關於Bean後處理器 AutowiredAnnotationBeanPostProcessor 的執行分析:
編寫如下程式碼:
public class DigInAutowired {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", Bean2.class);
beanFactory.registerSingleton("bean3", Bean3.class);
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 1.建立一個後處理器物件
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
processor.postProcessProperties(null,bean1,"bean1"); // 執行依賴注入@Autowired@Value
System.out.println(bean1);
}
}
debug進入到postProcessProperties方法中去:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 首先找到有沒有加@Autowired註解的屬性,方法,找到後封裝到 InjectionMetadata 中
InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//透過反射給屬性賦值,set方法反射呼叫等
metadata.inject(bean, beanName, pvs);
return pvs;
} catch (BeanCreationException var6) {
BeanCreationException ex = var6;
throw ex;
} catch (Throwable var7) {
Throwable ex = var7;
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
}
除此之外我們還可以使用反射的機制手動獲取@Autowird和@Value註解上的資訊:
public class DigInAutowired {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", Bean2.class);
beanFactory.registerSingleton("bean3", Bean3.class);
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 1.建立一個後處理器物件
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
// processor.postProcessProperties(null,bean1,"bean1"); // 執行依賴注入@Autowired@Value
// System.out.println(bean1);
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Bean1.class);
findAutowiringMetadata.setAccessible(true);
//反射呼叫該方法:獲取bean1上加了@Autowired和@Value註解上的資訊,包括成員變數和方法引數
Object injectionMetaData = (InjectionMetadata)findAutowiringMetadata.invoke(processor,"bean1", Bean1.class, null);
System.out.println(injectionMetaData);
}
}
4. 常見工廠後處理器
BeanFactory後處理器的作用:為BeanFactory提供擴充套件。
例如:
首先編寫如下Bean程式碼:
Config:
@Configuration
@ComponentScan("com.cherry.a05.component")
public class Config {
private Bean1 bean1;
@Bean
public Bean1 bean1(){
return new Bean1();
}
}
Bean1:
@Component
public class Bean1 {}
編寫主方法檢視此時能否獲取Bean物件
public class A05Application {
private static final Logger logger = LoggerFactory.getLogger(A05Application.class);
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
context.refresh(); //初始化容器
for(String name:context.getBeanDefinitionNames()){
System.out.println(name);
}
}
}
config
我們發現只有我們手動加入的bean,而組建掃描並未生效,因此被@Bean註解的方法也未加入到容器中。
因此我們們需要加入一個可以解析@@ComponentScan註解資訊的bean工廠後處理器:
public class A05Application {
private static final Logger logger = LoggerFactory.getLogger(A05Application.class);
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(ConfigurationClassPostProcessor.class);
// 掃描mybatias的Mapper介面,並將這些就介面加入到容器中
context.registerBean(MapperScannerConfigurer.class);
context.registerBean("config",Config.class);
context.refresh(); //初始化容器
for(String name:context.getBeanDefinitionNames()){
System.out.println(name);
}
}
}
此時再次執行:
config
bean2
bean3
bean4
bean1
ConfigurationClassPostProcessor處理器支援對@ComponentScan,,@Bean,@Import,@ImportResource 註解的解析
5. 工廠後處理器的模擬實現
5.1 元件掃描
public class A06ApplicationTest {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
//查詢類上有沒有加@ComponentScan註解
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if(componentScan != null){
//獲取註解上的屬性(包路徑)
for (String p : componentScan.basePackages()) {
// System.out.println(p); // com.cherry.a05.component
// 修改包名轉為路徑 --> 子包下的所有的類
String packagePath = "classpath*:"+p.replace(".","/")+"/**/*.class";
// System.out.println(packagePath);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = context.getResources(packagePath);
for(Resource res:resources){
// System.out.println(res);
MetadataReader reader = factory.getMetadataReader(res);
System.out.println(reader.getClassMetadata().getClassName());
// 判斷是否加入了@Component
System.out.println("是否加了@Component: "+reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
System.out.println("是否加了@Component及其派生註解: "+reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));
if(reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()) ||
reader.getAnnotationMetadata().hasAnnotation(Component.class.getName())){
// 建立一個BeanDefinition
AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
// 為BeanDefinition生成Bean Name
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
String beanName = beanNameGenerator.generateBeanName(bd, context.getDefaultListableBeanFactory());
// 將BeanDefinition加入到BeanFactory中
context.getDefaultListableBeanFactory().registerBeanDefinition(beanName, bd);
}
}
}
}
context.refresh();
System.out.println("===========");
for(String name:context.getBeanDefinitionNames()){
System.out.println(name);
}
}
}
執行結果如下:
com.cherry.a05.component.Bean2
是否加了@Component: true
是否加了@Component及其派生註解: false
com.cherry.a05.component.Bean3
是否加了@Component: true
是否加了@Component及其派生註解: false
com.cherry.a05.component.Bean4
是否加了@Component: false
是否加了@Component及其派生註解: true
09:19:43.994 [main] INFO com.cherry.a05.component.Bean2 -- 我被spring容器管理了...
09:19:44.011 [main] INFO com.cherry.a05.component.Bean3 -- 我被spring容器管理了...
09:19:44.012 [main] INFO com.cherry.a05.component.Bean4 -- 我被spring容器管理了...
===========
bean2
bean3
bean4
Process finished with exit code 0
把上述的元件掃描抽象出一個BeanFactoryPostProcessor:
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
// postProcessBeanFactory在context.refresh()時呼叫
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try {
//查詢類上有沒有加@ComponentScan註解
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if(componentScan != null){
//獲取註解上的屬性(包路徑)
for (String p : componentScan.basePackages()) {
// System.out.println(p); // com.cherry.a05.component
// 修改包名轉為路徑 --> 子包下的所有的類
String packagePath = "classpath*:"+p.replace(".","/")+"/**/*.class";
// System.out.println(packagePath);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(packagePath);
for(Resource res:resources){
// System.out.println(res);
MetadataReader reader = factory.getMetadataReader(res);
System.out.println(reader.getClassMetadata().getClassName());
// 判斷是否加入了@Component
System.out.println("是否加了@Component: "+reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
System.out.println("是否加了@Component及其派生註解: "+reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));
if(reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()) ||
reader.getAnnotationMetadata().hasAnnotation(Component.class.getName())){
// 建立一個BeanDefinition
AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
// 為BeanDefinition生成Bean Name
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
// 判斷 configurableListableBeanFactory 是否為 DefaultListableBeanFactory 的實現
if (configurableListableBeanFactory instanceof DefaultListableBeanFactory beanFactory) {
String beanName = beanNameGenerator.generateBeanName(bd, beanFactory);
// 將BeanDefinition加入到BeanFactory中
beanFactory.registerBeanDefinition(beanName, bd);
}
}
}
}
}
} catch (Exception e){
e.printStackTrace();
}
}
}
在主方法直接將bean工廠後處理器註冊到bean工廠中即可:
context.registerBean(ComponentScanPostProcessor.class);
5.2 對@Bean註解的解析
將@Bean標註的方法變成BeanDefinition並加入到容器中。
@SpringBootApplication
public class A06ApplicationTest {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
// 讀取Config類的資訊
MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/cherry/a05/Config.class"));
// 拿到所有被@Bean註解標記的方法
Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for(MethodMetadata metadata:methods){
System.out.println(metadata.toString());
// 將方法資訊生成對應的BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.setFactoryMethodOnBean(metadata.getMethodName(), "config");
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
AbstractBeanDefinition bd = builder.getBeanDefinition();
// 加入到BeanFactory中
context.getDefaultListableBeanFactory().registerBeanDefinition(metadata.getMethodName(),bd);
}
context.refresh();
System.out.println("===========");
for(String name:context.getBeanDefinitionNames()){
System.out.println(name);
}
}
}
5.3 對@Mapper註解的解析
public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) {
// 掃描Mapper包下的資源
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] resources = resolver.getResources("classpath:com/cherry/a05/mapper/**/*.class");
CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
for(Resource res:resources){
MetadataReader reader = metadataReaderFactory.getMetadataReader(res);
ClassMetadata classMetadata = reader.getClassMetadata();
// 判斷是否為介面
if (classMetadata.isInterface()) {
// 生成對應的 BeanDefinition
AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class).
addConstructorArgValue(classMetadata.getClassName())
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)//設定自動裝配
.getBeanDefinition();
AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
String beanName = generator.generateBeanName(bd, beanFactory);
beanFactory.registerBeanDefinition(beanName, bd);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistryPostProcessor.super.postProcessBeanFactory(beanFactory);
}
}