暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SpringBoot的入门(四)

IT分享 2020-01-10
294

SpringBoot-@Import 注解的工作原理

在没有接触SpringBoot的时候想要把一个对象注入到Spring容器中的方法:

1、可以使用@Component注解,代码如下:

  1. package com.boot.enable.imp.demo;

  2. import org.springframework.stereotype.Component;


  3. @Component

  4. public class Book {

  5. }

复制
  1. package com.boot.enable.imp.demo;


  2. import org.springframework.stereotype.Component;


  3. @Component

  4. public class User {

  5. }

复制

主函数:

  1. package com.boot.enable.imp.demo;

  2. import org.springframework.boot.SpringApplication;

  3. import org.springframework.boot.autoconfigure.SpringBootApplication;

  4. import org.springframework.context.ConfigurableApplicationContext;

  5. import org.springframework.context.annotation.Bean;

  6. /**

  7. * 普通得方式来装配得

  8. */

  9. @SpringBootApplication

  10. public class ImportApplication {

  11. @Bean

  12. public User createUser(){

  13. return new User();

  14. }

  15. public static void main(String[] args) {

  16. ConfigurableApplicationContext context =

  17. SpringApplication.run(ImportApplication.class, args);

  18. System.out.println(context.getBean(Book.class));

  19. System.out.println(context.getBean(User.class));

  20. context.close();

  21. }

  22. }

复制

运行的结果如下:

2、第二种方式:使用一个配置类来配置:

  1. package com.boot.enable.imp.demo;

  2. import org.springframework.boot.SpringApplication;

  3. import org.springframework.boot.autoconfigure.SpringBootApplication;

  4. import org.springframework.context.ConfigurableApplicationContext;

  5. import org.springframework.context.annotation.Bean;

  6. /**

  7. * 普通得方式来装配得

  8. */

  9. @SpringBootApplication

  10. public class ImportApplication {

  11. @Bean

  12. public Book book(){

  13. return new Book();

  14. }

  15. public static void main(String[] args) {

  16. ConfigurableApplicationContext context =

  17. SpringApplication.run(ImportApplication.class, args);

  18. System.out.println(context.getBean(Book.class));

  19. System.out.println(context.getBean(User.class));

  20. context.close();

  21. }

  22. }

复制

运行结果如下:

3、第三种方式:通过@Import的方式把这个对象引入进来:这个类型的实例将会交给spring容器去管理。

运行的结果如下:

原因所在:@Import这个注解的接口对应两个配置类:

A:ImportSelector                 B:ImportBeanDefinitionRegistrator

  1. package org.springframework.context.annotation;


  2. import java.lang.annotation.Documented;

  3. import java.lang.annotation.ElementType;

  4. import java.lang.annotation.Retention;

  5. import java.lang.annotation.RetentionPolicy;

  6. import java.lang.annotation.Target;


  7. @Target({ElementType.TYPE})

  8. @Retention(RetentionPolicy.RUNTIME)

  9. @Documented

  10. public @interface Import {

  11. Class<?>[] value();

  12. }

复制

在ImportSelector这个接口里面有一个方法:把返回当前的类的全路径的都实例化所有的对象都统统纳入到spring容器种去进行管理。

只要我去实现了下面接口的方法,只要这个方法里面传过来所有的对象都会统统的纳入到spring容器中去管理它。

  1. package org.springframework.context.annotation;


  2. import org.springframework.core.type.AnnotationMetadata;


  3. public interface ImportSelector {

  4. String[] selectImports(AnnotationMetadata var1);

  5. }

复制

代码如下:

  1. package com.boot.enable.imp.demo1;


  2. import org.springframework.context.annotation.ImportSelector;

  3. import org.springframework.core.type.AnnotationMetadata;


  4. public class BeanImportSelector implements ImportSelector {

  5. @Override

  6. public String[] selectImports(AnnotationMetadata annotationMetadata) {

  7. return new String[]{"com.boot.enable.imp.demo1.Book","com.boot.enable.imp.demo1.User"};

  8. }

  9. }

复制

主函数代码改下:

  1. package com.boot.enable.imp.demo1;

  2. import org.springframework.boot.SpringApplication;

  3. import org.springframework.boot.autoconfigure.SpringBootApplication;

  4. import org.springframework.context.ConfigurableApplicationContext;

  5. import org.springframework.context.annotation.Import;


  6. /**

  7. * 使用@Import方式来装配

  8. */

  9. @SpringBootApplication

  10. @Import(BeanImportSelector.class)

  11. public class ImportApplication1 {

  12. public static void main(String[] args) {

  13. ConfigurableApplicationContext context =

  14. SpringApplication.run(ImportApplication1.class, args);

  15. System.out.println(context.getBean(User.class));

  16. System.out.println(context.getBean(Book.class));

  17. context.close();

  18. }

  19. }

复制

运行结果如下:

4:第四种方式:ImportBeanefinitionRegistrator这个类也可以做到,代码如下:

  1. package com.boot.enable.imp.demo2;


  2. import org.springframework.beans.factory.config.BeanDefinition;

  3. import org.springframework.beans.factory.support.AbstractBeanDefinition;

  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. public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

  9. //beanDefinitionRegistry把一个对象注册到Spring容器中去管理

  10. @Override

  11. public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {

  12. //创建构建器对象

  13. BeanDefinitionBuilder bdb=BeanDefinitionBuilder.rootBeanDefinition(User.class);

  14. BeanDefinition beanDefinition = bdb.getBeanDefinition();

//第一个参数是别名

  1. beanDefinitionRegistry.registerBeanDefinition("user",beanDefinition);


  2. BeanDefinitionBuilder bdb1=BeanDefinitionBuilder.rootBeanDefinition(Book.class);

  3. BeanDefinition beanDefinition1 = bdb1.getBeanDefinition();

  4. beanDefinitionRegistry.registerBeanDefinition("book",beanDefinition1);

  5. }

  6. }

复制

主函数的代码如下:

  1. package com.boot.enable.imp.demo2;

  2. import com.boot.enable.imp.demo1.BeanImportSelector;

  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. * 使用@Import方式来装配

  9. */

  10. @SpringBootApplication

  11. //@Import({User.class,Book.class})

  12. @Import(MyBeanDefinitionRegistrar.class)

  13. public class ImportApplication1 {

  14. public static void main(String[] args) {

  15. ConfigurableApplicationContext context =

  16. SpringApplication.run(ImportApplication1.class, args);

  17. System.out.println(context.getBean("user",User.class));

  18. System.out.println(context.getBean("book",Book.class));

  19. context.close();

  20. }

  21. }

复制

运行的结果如下:

第三种和第四种方法的区别:第四种可以注入参数和属性到spring容器中。

小节总结:@Import注解的工作原理,就是对应的类去实现接口中的方法从而把对象到spring容器中去。


注解装配监控器实现(BeanDefinitionProcessor回调)-如何去做自己的组件

实现的功能:看哪些对象被装配到spring容器中去,就把它对应的实例给打印出来。

步骤   1、自定义注解:用来扫描包的路径的:

  1. package com.boot.enable.sample;


  2. import org.springframework.context.annotation.Import;


  3. import java.lang.annotation.*;


  4. @Target({ElementType.TYPE})

  5. @Retention(RetentionPolicy.RUNTIME)

  6. @Documented

  7. @Import(ScannerPackageRegister.class)

  8. //指定扫描所有的包

  9. public @interface EnableScanner {

  10. String[] packages();

  11. }

复制

2、主类函数如下:

  1. package com.boot.enable.sample;


  2. import org.springframework.boot.SpringApplication;

  3. import org.springframework.boot.autoconfigure.SpringBootApplication;

  4. import org.springframework.scheduling.annotation.EnableAsync;


  5. @SpringBootApplication

  6. //启用监控扫描类的注解

  7. @EnableScanner(packages = {"com.boot.enable.sample.bean","com.boot.enable.sample.vo"})

  8. public class ScannerPackageApplication {

  9. public static void main(String[] args) {

  10. SpringApplication.run(ScannerPackageApplication.class,args);

  11. }

  12. }

复制

3、ScannerPackageRegister这个类的代码如下:

  1. package com.boot.enable.sample;

  2. import org.springframework.beans.factory.config.BeanDefinition;

  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 java.util.Arrays;

  8. import java.util.List;

  9. public class ScannerPackageRegister implements ImportBeanDefinitionRegistrar {

  10. //AnnotationMetadata:通过它来获取到EnableScanner这个注解中packages这个属性对应的值

  11. @Override

  12. public void registerBeanDefinitions(AnnotationMetadata annotationMetadata,

  13. BeanDefinitionRegistry beanDefinitionRegistry) {

  14. String [] args= (String[])annotationMetadata

  15. .getAnnotationAttributes(EnableScanner.class.getName()).get("packages");


  16. //packages这个拿出来是一个数组,要转成集合后面好操作

  17. List<String> packages= Arrays.asList(args);

  18. System.out.println(packages);

  19. //MyBeanDefinitionProcessor通过这个类来进行统一的实例化

  20. //在实例化的前后都会进行拦截的处理。

  21. BeanDefinitionBuilder bdb=BeanDefinitionBuilder.rootBeanDefinition(MyBeanDefinitionProcessor.class);

  22. //把这个集合装配到spring容器中去。

  23. bdb.addPropertyValue("packages",packages);

  24. BeanDefinition beanDefinition = bdb.getBeanDefinition();

  25. beanDefinitionRegistry.registerBeanDefinition(MyBeanDefinitionProcessor.class.getName(),beanDefinition);


  26. }

  27. }

复制

4、要装配类的的代码如下:

  1. package com.boot.enable.sample;

  2. import org.springframework.beans.BeansException;

  3. import org.springframework.beans.factory.config.BeanPostProcessor;

  4. import java.util.List;

  5. //当类被装配到Spring容器中是需要通过这个接口的,会回调这个接口中postProcessBeforeInitialization这个方法的

  6. public class MyBeanDefinitionProcessor implements BeanPostProcessor {

  7. private List<String> packages;

  8. //等会要注入的所以要提供set方法

  9. public void setPackages(List<String> packages) {

  10. this.packages = packages;

  11. }


  12. @Override

  13. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

  14. for(String pack:packages){

  15. if(bean.getClass().getName().startsWith(pack)){

  16. System.out.println("-----------"+bean.getClass().getName());

  17. }

  18. }

  19. return bean;

  20. }

  21. }

复制

运行的结果如下:

小节总结:这就是使用@Import注解的工作原理来模拟一个监控被注入到spring容器中的类的实例,一开始是不知道哪些类被装配到spring容器中的。相当于做一个过滤器来判断哪些类被装配到spring容器中,从而做一个监控的作用。

归根结低还是@Import。比如可以做劫持的操作。

未完待续,如果觉的哪里不好的话,请各位大佬指出缺点,互相学习。嘻嘻

如果想要代码的话可以加下qq群:797853299。

然后请关注下朋友的订阅号,欢迎大家去找茬:



文章转载自IT分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论