springboot自动装配

其实springboot的自动装配流程的关键点是通过@Import注解和对应的ImportSelector接口实现,加入相关需要导入的配置文件properties,配置文件中默认配置了需要导入的类,结合过滤规则和项目中是否导入相应的jar来确定是否需要导入相关的类。

 

首先介绍下@Import和ImportSelector接口的使用。注意:我这里是搭建的源码环境:

普通的pojo:

package mytest.person;
​
public class Person2  {
​
    public Person2() {
        System.out.println("person2...");
    }
    private int age;
    private String name;
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
}

实现接口ImportSelector:

package mytest.person;
​
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class Person2Selector implements ImportSelector {
​
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 这里写上述的pojo Person2的全类名
        return new String[]{"mytest.person.Person2"};
    }
​
    private int age;
    private String name;
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
}

config的配置类:

package mytest;
​
import mytest.person.Person2Selector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
​
@Configuration
@Import(Person2Selector.class)
public class Config {
​
}

 

测试客户端:

package mytest;
​
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
​
public class Client {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext
                ap = new AnnotationConfigApplicationContext(Config.class);
    }
}

执行后,打印出输出结果:

person2...

 

可以发现上述的步骤中,有一个非常灵活的地方:

public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 这里写上述的pojo Person2的全类名
        return new String[]{"mytest.person.Person2"};
    }

 

这里可以返回多个导入需要的实例的,只需要逗号隔开就行。所以可以通过配置文件读取的形式来读入。

 

简易版本的springboot的自动装配

 

创建一个autoconfig.properties文件:我这里只是加入需要导入的三个类:

mytest.MyAutoConfig=mytest.person.Person2,mytest.person.Person,mytest.person.Person3

加一个自动装配的注解:

package mytest;
​
import org.springframework.context.annotation.Import;
​
import java.lang.annotation.*;
​
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(MyAutoConfigurationImportSelector.class)
public @interface MyAutoConfig {
}

ImportSelector的具体实现:

package mytest;
​
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;
​
import java.io.FileInputStream;
import java.util.Properties;
​
public class MyAutoConfigurationImportSelector implements ImportSelector {
​
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        Properties properties = new Properties();
        try {
            // 读取对应的properties文件
            properties.load(new FileInputStream("D:\\jeffchan\\other-meterial\\spring-framework\\spring-my-test\\src\\main\\resources\\META-INF\\autoconfig.properties"));
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        // 获取对应要装配的类配置信息
        String objClass = (String)properties.get(MyAutoConfig.class.getName());
        // 直接返回相应的结果。(其实就是将需要导入的类的全类名通过String数组的方式返回)
        return StringUtils.isEmpty(objClass) ? new String[0] : objClass.split(",");
    }
}

 

相应的配置类需要修改一个:

package mytest;
​
import org.springframework.context.annotation.Configuration;
​
@Configuration
@MyAutoConfig // 换成需要自动装配的注解
public class Config {
​
}

还是执行打印结果:

springboot自动装配

发现需要导入的类都导入了:这里面最灵活的地方还是在ImportSelector接口的实现方法中,比如这里可以加入需要过滤的规则等一些限制。

 

上述的本质流程其实都是在产生beanDefination的流程。就是将需要导入的类放入到工厂类的beanDefinationMap中,然后在容器刷新的时候,会创建对应的实例放入到单例缓存池中。那么后续需要时候可以直接注入对应的实例。spring源码中还提供了对bean定义和bean实例修改的位置。比如BeanFactoryProcessor和BeanPostProcessor等接口可以灵活的修改bean定义和bean实例。

上一篇:Java IO学习笔记六:NIO到多路复用


下一篇:安卓源码中编译并放入平台运行