SpringBoot的入门(四)

简介: SpringBoot的入门(四)

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. }
  6. package com.boot.enable.imp.demo;

  7. import org.springframework.stereotype.Component;

  8. @Component
  9. public class User {
  10. }

主函数:

  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。比如可以做劫持的操作。

相关文章
|
3月前
|
Java 容器 Spring
SpringBoot入门(六)
SpringBoot入门(六)
|
3月前
|
JSON Java API
SpringBoot入门(八)
SpringBoot入门(八)
|
3月前
|
Java Spring 容器
SpringBoot的入门(三)
SpringBoot的入门(三)
|
3月前
|
Java 应用服务中间件 nginx
SpringBoot入门(九)
SpringBoot入门(九)
|
3月前
|
消息中间件 NoSQL Java
SpringBoot的入门(五)
SpringBoot的入门(五)
|
3月前
|
NoSQL Java Redis
SpringBoot的入门(一)
SpringBoot的入门(一)
|
3月前
|
Java Spring 容器
SpringBoot的入门(二)
SpringBoot的入门(二)
|
3月前
|
JSON Java 数据格式
SpringBoot入门(七)
SpringBoot入门(七)
|
3月前
|
Java API 容器
SpringBoot入门(十)
SpringBoot入门(十)
|
6月前
|
Java 数据库连接 Maven