SpringBoot原理篇(玩点花活666)

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都输出了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九天狐揽月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值