SpringBoot框架(4)-- 类装配及Bean装配监听器
1、普通方式装配类对象
(1)添加带有@Bean注解的方法
User.java(带@Component注解)
1 package com.demo.boot.bootenable.beanDemo1; 2 3 import org.springframework.stereotype.Component; 4 5 @Component 6 public class User { 7 }
(2)需要装配的类添加@Component注解
Book.java(不带@Component注解)
1 package com.demo.boot.bootenable.beanDemo1; 2 3 public class Book { 4 }
==》打印
1 package com.demo.boot.bootenable.beanDemo1; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.context.ConfigurableApplicationContext; 6 import org.springframework.context.annotation.Bean; 7 8 /** 9 * 普通方式装配类对象 10 * (1)添加带有@Bean注解的方法 11 * (2)需要装配的类添加@Component注解 12 */ 13 @SpringBootApplication 14 public class BootEnableApplication { 15 16 @Bean 17 public Book createBook(){ 18 return new Book(); 19 } 20 21 public static void main(String[] args) { 22 ConfigurableApplicationContext context = SpringApplication.run(com.demo.boot.bootenable.beanDemo1.BootEnableApplication.class); 23 User user = context.getBean(User.class); 24 System.out.println(user); 25 26 Book book = context.getBean(Book.class); 27 System.out.println(book); 28 context.close(); 29 } 30 }
com.demo.boot.bootenable.beanDemo1.User@3301500b
com.demo.boot.bootenable.beanDemo1.Book@24b52d3e
2、使用@Import方式装配类对象
准备两个测试类User.java和Book.java
1 package com.demo.boot.bootenable.beanDemo2; 2 3 public class User { 4 }
1 package com.demo.boot.bootenable.beanDemo2; 2 3 public class Book { 4 }
(1)方式1==》@Import({User.class,Book.class}) //直接添加需要装配的类
==》代码结构
1 package com.demo.boot.bootenable.beanDemo2; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.context.ConfigurableApplicationContext; 6 import org.springframework.context.annotation.Import; 7 8 /** 9 * 使用@Import方式装配类对象 10 */ 11 @SpringBootApplication 12 @Import({User.class,Book.class})//方式1==》直接添加需要装配的类 13 public class BootEnableApplication { 14 public static void main(String[] args) { 15 ConfigurableApplicationContext context2 = SpringApplication.run(BootEnableApplication.class); 16 User user = context2.getBean(User.class); 17 System.out.println(user); 18 19 Book book = context2.getBean(Book.class); 20 System.out.println(book); 21 context2.close(); 22 } 23 }
==》输出
com.demo.boot.bootenable.beanDemo2.User@24855019
com.demo.boot.bootenable.beanDemo2.Book@3abd581e
(2)方式2==》@Import(BeanImportSelector.class) //BeanImportSelector重写ImportSelector类的selectImport方法
==》代码结构
1 package com.demo.boot.bootenable.beanDemo2; 2 3 import org.springframework.context.annotation.ImportSelector; 4 import org.springframework.core.type.AnnotationMetadata; 5 6 public class BeanImportSelector implements ImportSelector { 7 @Override 8 public String[] selectImports(AnnotationMetadata annotationMetadata) { 9 return new String[]{ 10 "com.demo.boot.bootenable.beanDemo2.Book", 11 "com.demo.boot.bootenable.beanDemo2.User" 12 }; 13 } 14 }
1 package com.demo.boot.bootenable.beanDemo2; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.context.ConfigurableApplicationContext; 6 import org.springframework.context.annotation.Import; 7 8 /** 9 * 使用@Import方式装配类对象 10 */ 11 @SpringBootApplication 12 //@Import({User.class,Book.class})//方式1==》直接添加需要装配的类 13 @Import(BeanImportSelector.class)//方式2==》BeanImportSelector重写ImportSelector类的selectImport方法 14 public class BootEnableApplication { 15 public static void main(String[] args) { 16 ConfigurableApplicationContext context2 = SpringApplication.run(BootEnableApplication.class); 17 User user = context2.getBean(User.class); 18 System.out.println(user); 19 20 Book book = context2.getBean(Book.class); 21 System.out.println(book); 22 context2.close(); 23 } 24 }
==》输出
com.demo.boot.bootenable.beanDemo2.User@88d6f9b
com.demo.boot.bootenable.beanDemo2.Book@47d93e0d
(3)方式3==》@Import(MyBeanDefinitionRegistrar.class) //MyBeanDefinitionRegistrar重写ImportBeanDefinitionRegistrar类的registerBeanDefinitions方法
==》代码结构
1 package com.demo.boot.bootenable.beanDemo3; 2 3 import org.springframework.beans.factory.config.BeanDefinition; 4 import org.springframework.beans.factory.support.BeanDefinitionBuilder; 5 import org.springframework.beans.factory.support.BeanDefinitionRegistry; 6 import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; 7 import org.springframework.core.type.AnnotationMetadata; 8 9 /** 10 * ImportBeanDefinitionRegistrar可以为装配对象添加额外的属性 11 */ 12 public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { 13 @Override 14 public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { 15 BeanDefinitionBuilder userBDB = BeanDefinitionBuilder.rootBeanDefinition(User.class); 16 BeanDefinition userBD = userBDB.getBeanDefinition(); 17 beanDefinitionRegistry.registerBeanDefinition("user",userBD); 18 19 BeanDefinitionBuilder bookBDB = BeanDefinitionBuilder.rootBeanDefinition(Book.class); 20 BeanDefinition bookBD = bookBDB.getBeanDefinition(); 21 beanDefinitionRegistry.registerBeanDefinition("book",bookBD); 22 } 23 }
1 package com.demo.boot.bootenable.beanDemo3; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.context.ConfigurableApplicationContext; 6 import org.springframework.context.annotation.Import; 7 8 /** 9 * 使用@Import方式装配类对象 10 */ 11 @SpringBootApplication 12 //@Import({User.class,Book.class})//方式1==》直接添加需要装配的类 13 //@Import(BeanImportSelector.class)//方式2==》BeanImportSelector重写ImportSelector类的selectImport方法 14 @Import(MyBeanDefinitionRegistrar.class)//方式3==》MyBeanDefinitionRegistrar重写ImportBeanDefinitionRegistrar类的registerBeanDefinitions方法 15 public class BootEnableApplication { 16 public static void main(String[] args) { 17 ConfigurableApplicationContext context3 = SpringApplication.run(BootEnableApplication.class); 18 User user = context3.getBean("user", User.class); 19 System.out.println(user); 20 21 Book book = context3.getBean("book", Book.class); 22 System.out.println(book); 23 context3.close(); 24 } 25 }
==》输出
com.demo.boot.bootenable.beanDemo3.User@4d0402b
com.demo.boot.bootenable.beanDemo3.Book@2fa7ae9
备注:以上demo中,都是指定需要装配的类,不指定则不会自动自动装配
3、Bean装配监听器
bean在装配过程中会执行一系列方法,其中有postProcessBeforeInitialization --> afterPropertiesSet --> init-method -- > postProcessAfterInitialization。
(1)postProcessBeforeInitialization方法,在bean初始化之前执行
(2)afterPropertiesSet方法,初始化bean的时候执行
(3)nit-method方法,初始化bean的时候执行
(4)postProcessAfterInitialization方法,在bean初始化之后执行。
因此,我们可以在装配时,进行拦截处理。这里demo选用重写postProcessBeforeInitialization方法
代码结构
3.1 创建类 MyBeanDefinitionProcessor继承BeanPostProcessor,添加属性packages的构造器,并重写postProcessBeforeInitialization方法,实现类装配前打印。
1 package com.demo.boot.bootenable.smple; 2 3 import org.springframework.beans.BeansException; 4 import org.springframework.beans.factory.config.BeanPostProcessor; 5 6 import java.util.ArrayList; 7 8 public class MyBeanDefinitionProcessor implements BeanPostProcessor { 9 10 private ArrayList<String> packages; 11 12 public ArrayList<String> getPackages() { 13 return packages; 14 } 15 16 public void setPackages(ArrayList<String> packages) { 17 this.packages = packages; 18 } 19 20 @Override 21 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 22 23 for (String pack : packages) { 24 if (bean.getClass().getName().startsWith(pack)) { 25 System.out.println("instance name:" + bean.getClass().getName()); 26 } 27 } 28 return bean; 29 } 30 }
3.2 创建类ScannerPackegeRegistar implements ImportBeanDefinitionRegistrar,重写registerBeanDefinitions方法,把自定义的MyBeanDefinitionProcessor注册进去。
1 package com.demo.boot.bootenable.smple; 2 3 import org.springframework.beans.factory.support.BeanDefinitionBuilder; 4 import org.springframework.beans.factory.support.BeanDefinitionRegistry; 5 import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; 6 import org.springframework.core.type.AnnotationMetadata; 7 import org.springframework.stereotype.Component; 8 9 import java.util.Arrays; 10 import java.util.List; 11 12 @Component 13 public class ScannerPackegeRegistar implements ImportBeanDefinitionRegistrar { 14 /** 15 * 注册实体对象被装配前回调方法 16 * @param annotationMetadata 17 * @param beanDefinitionRegistry 18 */ 19 @Override 20 public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { 21 String[] strArr = (String[]) annotationMetadata 22 .getAnnotationAttributes(EnableScanner.class.getName()) 23 .get("packages"); 24 25 List<String> packages = Arrays.asList(strArr); 26 System.out.println(packages); 27 BeanDefinitionBuilder dbd = BeanDefinitionBuilder.rootBeanDefinition(MyBeanDefinitionProcessor.class); 28 dbd.addPropertyValue("packages", packages); 29 30 beanDefinitionRegistry.registerBeanDefinition(MyBeanDefinitionProcessor.class.getName(), dbd.getBeanDefinition()); 31 } 32 33 }
3.3 自定义注解EnableScanner
1 package com.demo.boot.bootenable.smple; 2 3 import org.springframework.context.annotation.Import; 4 import java.lang.annotation.*; 5 6 @Target({ElementType.TYPE}) 7 @Retention(RetentionPolicy.RUNTIME) 8 @Documented 9 @Import(ScannerPackegeRegistar.class) 10 public @interface EnableScanner { 11 String[] packages(); 12 }
3.4 创建Person.java、Student.java和UserVO.java类
1 package com.demo.boot.bootenable.smple.bean; 2 3 import org.springframework.stereotype.Component; 4 5 @Component 6 public class Person { 7 }
1 package com.demo.boot.bootenable.smple.bean; 2 3 import org.springframework.stereotype.Component; 4 5 @Component 6 public class Student { 7 }
1 package com.demo.boot.bootenable.smple.vo; 2 3 import org.springframework.stereotype.Component; 4 5 @Component 6 public class UserVO { 7 }
3.5 Application
1 package com.demo.boot.bootenable.smple; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.context.ConfigurableApplicationContext; 6 7 @SpringBootApplication 8 @EnableScanner(packages = {"com.demo.boot.bootenable.smple.bean", "com.demo.boot.bootenable.smple.vo"})//启用监控扫描类的注解 9 public class ScannerPackegeApplication { 10 public static void main(String[] args) { 11 ConfigurableApplicationContext context = SpringApplication.run(ScannerPackegeApplication.class, args); 12 13 context.close(); 14 } 15 }
输出结果
instance name:com.demo.boot.bootenable.smple.bean.Person
instance name:com.demo.boot.bootenable.smple.bean.Student
instance name:com.demo.boot.bootenable.smple.vo.UserVO
总结思路
1、把类装配到SpringBoot容器管理主要分两大类
(1)普通方式:直接在类上加@Component注解,或者在创建对象方法加上@Bean注解
(2)通过@Import注解:直接指定需要装配的类,传入
重写ImportSelector类的selectImport方法的类,
或重写ImportBeanDefinitionRegistrar类的registerBeanDefinitions方法
2、Bean装配监听器
(1)定义注解,接受需要装配类的包名
(2)创建ImportBeanDefinitionRegistrar的子类ScannerPackegeRegistar,重写registerBeanDefinitions方法,作用是把监听器注册到SpringBoot初始化Bean的过程中。
(3)创建BeanPostProcessor的子类MyBeanDefinitionProcessor,重写postProcessBeforeInitialization方法,作用是监听在bean初始化前装配的类。