SpringBoot原理篇
Bean的加载方式(一)
<!-- 声明自定义Bean -->
<bean id="cat" class="com.wuyang.bean.Cat"></bean>
<bean class="com.wuyang.bean.Dog"></bean>
<!-- 声明第三方Bean -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"></bean>
Bean的加载方式(二)
- 使用@Component及其衍生注解@Controller,@Servcie,@Repository定义bean
@Service
public class UserServiceImpl1 implements UserService {
@Override
public void check() {
System.out.println(" user service 1 。。。。。。。。");
}
}
- 使用@Bean定义第三方Bean,并将所在类定义为配置类或Bean
//@Component
@Configuration
public class DbConfig {
@Bean
public DruidDataSource druidDataSource() {
DruidDataSource ds = new DruidDataSource();
return ds;
}
}
Bean的加载方式(三)
- 注解方式声明配置类
@Configuration
@ComponentScan({"com.wuyang.bean", "com.wuyang.config"})
public class SpringConfig {
}
@Configuration配置项不用于被扫描可以省略
FactoryBean
@Component
public class DogFactroyBean implements FactoryBean<Dog> {
@Override
public Dog getObject() throws Exception {
Dog dog = new Dog();
return dog;
}
@Override
public Class<?> getObjectType() {
return Dog.class;
}
@Override
public boolean isSingleton() {
return !FactoryBean.super.isSingleton(); // 不是单例,那么每次用FactoryBean造出的狗的对象不一样
}
}
public class App3 {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println(ac.getBean("dogFactroyBean"));
System.out.println(ac.getBean("dogFactroyBean"));
System.out.println(ac.getBean("dogFactroyBean"));
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/852
b0baa2e84475cb35a88e1fc1d1e1d.png#pic_center)
加载配置类并加载配置文件
@Configuration
@Component
@ImportResource("applictionContext1.xml")
public class SpringConfig666 {
}
proxyBeanMethods
这个代理Bean方法默认是true,这里设置为false
@Configuration(proxyBeanMethods = false)
public class SpringConfig67 {
@Bean
public Cat cat() {
return new Cat();
}
}
public class App67 {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig67.class);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
System.out.println("================================================");
SpringConfig67 springConfig67 = ac.getBean("springConfig67", SpringConfig67.class);
System.out.println(springConfig67.cat());
System.out.println(springConfig67.cat());
System.out.println(springConfig67.cat());
System.out.println(ac.getBean("cat"));
System.out.println(ac.getBean("cat"));
System.out.println(ac.getBean("cat"));
}
}
可以看到如果把proxyBeanMethods = false,那么以后里面的bean再调用这个cat方法,每次造的对象不是同一个对象
如果把proxyBeanMethods = true,那么以后里面的bean再调用这个cat方法,每次造的对象不是同一个对象,@Configuration默认不设置,默认proxyBeanMethods = true
Bean的加载方式(四)
- 使用@Import注解导入要注入的bean对应的字节码
@Import({Dog.class})
@Configuration(proxyBeanMethods = true)
public class SpringConfig4 {
}
- 被导入的bean无需使用注解声明为bean
public class Dog {
}
// 此形式可以有效降低源代码与Spring技术的耦合度,在spring技术底层与诸多框架的整合中大量使用
- 使用@Import注解导入配置类也无需再声明其是一个配置类就可以把配置类注册为一个Bean
- 并且配置类里面的bean也会注入
//@Configuration
public class DbConfig {
@Bean
public DruidDataSource druidDataSource() {
DruidDataSource ds = new DruidDataSource();
return ds;
}
}
@Import({Dog.class, DbConfig.class})
@Configuration(proxyBeanMethods = true)
public class SpringConfig4 {
}
Bean的加载方式(五)
- 使用上下文对象在容器初始化完毕后注入bean
public class App5 {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig4.class);
ac.registerBean("tom", Cat.class, 0);
ac.registerBean("tom", Cat.class, 1);
ac.registerBean("tom", Cat.class, 2);
ac.registerBean("tom", Cat.class, 3);
ac.register(Mouse.class);
for (String beanName : ac.getBeanDefinitionNames()) {
System.out.println(beanName);
}
System.out.println(ac.getBean(Cat.class));
}
}
输出结果
Bean的加载方式(六)
导入实现了ImportSelector接口的类,实现对导入源的编程式处理
public class MyImporterSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
System.out.println(importingClassMetadata.getClassName()); // @Import导入了当前类的所在类的类名
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(
"org.springframework.context.annotation.ComponentScan"); // @Import导入了当前类的所在类 里面的注解锁包含的属性
System.out.println(annotationAttributes);
boolean flag = importingClassMetadata.hasAnnotation(
"org.springframework.context.annotation.Configuration"); // @Import导入了当前类的所在类 是否包含这个注解
System.out.println(flag);
if (flag) {
return new String[]{"com.wuyang.bean.Cat"}; // 如果包含@Configuration这个类就选择注入Cat
} else {
return new String[]{"com.wuyang.bean.Dog"}; // 如果不包含@Configuration这个类就选择注入Dog
}
}
}
下面编写了一个配置类,使用@Import导入MyImportSelector
@Import(MyImporterSelector.class)
@Configuration
//@ComponentScan("com.wuyang")
public class SpringConfig8 {
}
public class App8 {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig8.class);
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
Bean的加载方式(七)
导入实现了ImportBeanDefinitionRegistrar接口的类,通过BeanDefinition的注册器注册实名bean,实现对容器中bean的裁定,例如对现有bean的覆盖,进行达成不修改源代码的情况下更换实现的效果
public class MyImportDefinitionRegisterar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();
registry.registerBeanDefinition("yellow", beanDefinition);
}
}
@Import(MyImportDefinitionRegisterar.class)
@Configuration
public class SpringConfig9 {
}
public class App9 {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig9.class);
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
Bean的加载方式(八)
导入实现了BeanDefinitionRegistryPostProcessor接口的类,通过BeanDefinition的注册器注册实名bean,实现对容器中bean的最终裁定
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserServiceImpl1.class).getBeanDefinition();
registry.registerBeanDefinition("red 3", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
@Import({UserServiceImpl1.class, Registerar1.class, Registerar2.class, MyPostProcessor.class})
public class SpringConfig68 {
}
public class App68 {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig68.class);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
导入的类
public class Registerar1 implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserServiceImpl1.class).getBeanDefinition();
registry.registerBeanDefinition("yellow 2", beanDefinition);
}
}
public class Registerar2 implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserServiceImpl1.class).getBeanDefinition();
registry.registerBeanDefinition("blue 2", beanDefinition);
}
}
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserServiceImpl1.class).getBeanDefinition();
registry.registerBeanDefinition("red 3", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
输出结果
这是基于jdk17,可以看出beanDifinition无论有没有对Bean重新注册,或者对Bean做了后置处理,其输出还是对每一次修改的Bean都输出来,因此这一点和原理Jdk8有很大的不同,8会不断的覆盖,有优先级和顺序的差别,而17是每一次修改的beanName都输出了