SpringBoot底层注解

文章目录


前言

本文主要讲诉@Configuration、@Import、@Conditional、@ImportResource、@ConfigurationProperties注解。

先将实体类给大家,方便下面测试:

get、set、构造器大家自己添加,这里我用的是ToString等注解(以后会出文章讲诉)所以没写这些,就不列出来了。

java 复制代码
public class Pet {
    private String name;

}
=================================
public class User {
    private String name;
    private Integer age;
    private Pet pet;
}
============================
public class Car {
    private String brand;
    private String price;
}

一、@Configuration

1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的,所谓单实例跟我们在Spring中了解的bean创建对象的单实例是一样的,就是在调用getBean方法创建相同类型实例对象时,这些对象的地址相同(即无论创建多少对象,都是同一个对象)。多实例就是每次创建对象都重新创建一个不同地址的新对象。

2、配置类本身也是组件。

3、proxyBeanMethods:代理bean的方法。

Full模式(proxyBeanMethods = true)(保证每个@Bean方法被调用多少次返回的组件都是单实例的)(默认)

Lite模式(proxyBeanMethods = false)(每个@Bean方法被调用多少次返回的组件都是新创建的)

配置类:

java 复制代码
@Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {

    /**
     * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
     * @return
     */
    @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
    public User user01(){
        User zhangsan = new User("zhangsan", 18,tomcatPet());
        //user组件依赖了Pet组件
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }
}

SpingBoot启动类

java 复制代码
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.dragon.boot")
public class MainApplication {

    public static void main(String[] args) {
    //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

    //2、查看容器里面的组件
    //    String[] names = run.getBeanDefinitionNames();
    //    for (String name : names) {
    //        System.out.println(name);
    //    }

    //3、从容器中获取组件
        Pet tom01 = run.getBean("tom", Pet.class);
        Pet tom02 = run.getBean("tom", Pet.class);
        System.out.println("组件:"+(tom01 == tom02));

    //4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);

    //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
        //保持组件单实例
        User user = bean.user01();
        User user1 = bean.user01();
        System.out.println(user == user1);

        User user01 = run.getBean("user01", User.class);
        Pet tom = run.getBean("tom", Pet.class);

        System.out.println("用户的宠物:"+(user01.getPet() == tom));
    }
}

看运行结果分析:

  • 组件:true
    配置类中我用的Full模式:@Configuration(proxyBeanMethods = true) ,当然就是单实例模式,所有创建的对象都是同一个对象。
  • com.dragon.boot.config.MyConfig SpringCGLIB$$0@283e8358
    这个输出是我getBean获取的配置类组件,可以看出配置类本身也是组件。
  • 用户的宠物:true
    当我开启单实例模式时,就能够处理依赖关系,这里我创建的组件宠物==用户组件里的宠物,User zhangsan = new User("zhangsan", 18,tomcatPet());。我创建的用户组件时就是调用的tomcatPet(),因为是单实例模式,所以我在创建用户调用创建的宠物和直接创建的宠物都是同一个对象。

启动类中我写了个查看容器里面的组件的方法,注释掉了,可以运行,在控制台Ctrl+F搜索查看注册的组件。

将proxyBeanMethods 属性改成false,运行结果就变成了false。

总结:

  • 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
  • 配置 类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(默认)

二、@Import导入组件

@Bean、@Component、@Controller、@Service、@Repository,它们是Spring的基本标签,在Spring Boot中并未改变它们原来的功能。

@ComponentScan在Spring学习中大家一定接触了吧,就是开启组件扫描。

Import({User.class、DBHelper.class})会给容器中自动创建出User、DBHelper组件,默认组件的名字就是全类名。如果创建多个组件就在在大号内添加,用逗号隔开。

java 复制代码
@Import({User.class,DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
	//....
}

启动类:

java 复制代码
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

//...

//5、获取组件
String[] beanNamesForType = run.getBeanNamesForType(User.class);

for (String s : beanNamesForType) {
    System.out.println(s);
}

三、@Conditional条件装配

条件装配:满足Conditional指定的条件,则进行组件注入

这里用@ConditionalOnMissingBean举例说明:

  • @ConditionalOnMissingBean(name = "tt")
    用在类上:没有tt名字的Bean时才会将类里所有配置注册成组件
    用在方法上:没有tt名字的Bean时才会将改方法注册成组件
java 复制代码
@Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类 == 配置文件
@Import({User.class})
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {
    /**
     * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
     * @return
     */
    @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
    public User user01(){
        User zhangsan = new User("zhangsan", 18,tomcatPet());
        //user组件依赖了Pet组件
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet(){
        return new Pet("tomcat");
    }
}

启动类:

java 复制代码
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

    //2、查看容器里面的组件
    String[] names = run.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }

    boolean tom = run.containsBean("tom");//是否包含某个组件
    System.out.println("容器中Tom组件:"+tom);//false

    boolean user01 = run.containsBean("user01");
    System.out.println("容器中user01组件:"+user01);//true

    boolean tom22 = run.containsBean("tom22");
    System.out.println("容器中tom22组件:"+tom22);//true

四、@ImportResource导入Spring配置文件

公司项目使用bean.xml文件生成配置bean,然而你为了省事,想继续复用bean.xml,@ImportResource粉墨登场。

bean.xml:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="haha" class="com.dragon.boot.bean.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>

    <bean id="hehe" class="com.atguigu.boot.bean.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>

复用方法:

java 复制代码
@ImportResource("classpath:bean.xml")
public class MyConfig {
	//...
}

启动类测试:

java 复制代码
//1、返回我们IOC容器
    ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

	boolean haha = run.containsBean("haha");
	boolean hehe = run.containsBean("hehe");
	System.out.println("haha:"+haha);//true
	System.out.println("hehe:"+hehe);//true

返回true,说明注册成了组件。

五、@ConfigurationProperties配置绑定

使用Java读取到properties文件中的内容,并且把它封装到JavaBean中

传统方法:

java 复制代码
public class getProperties {
     public static void main(String[] args) throws FileNotFoundException, IOException {
         Properties pps = new Properties();
         pps.load(new FileInputStream("a.properties"));
         Enumeration enum1 = pps.propertyNames();//得到配置文件的名字
         while(enum1.hasMoreElements()) {
             String strKey = (String) enum1.nextElement();
             String strValue = pps.getProperty(strKey);
             System.out.println(strKey + "=" + strValue);
             //封装到JavaBean。
         }
     }
 }

SpringBoot的两种方法:

  • @ConfigurationProperties + @Component
    假设有配置文件application.properties
properties 复制代码
mycar.brand=BYD
mycar.price=100000

只有在容器中的组件,才会拥有SpringBoot提供的强大功能,所以Bean对象类注册成组件

下面的prefix是指属性前缀

java 复制代码
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
...
}
  • @EnableConfigurationProperties + @ConfigurationProperties
    1.开启Car配置绑定功能
    2.把这个Car这个组件自动注册到容器中

配置类:

java 复制代码
@EnableConfigurationProperties(Car.class)
public class MyConfig {
 //...
}

Car类:

java 复制代码
@ConfigurationProperties(prefix = "mycar")
public class Car {
 //...
}

HelloController类:

java 复制代码
@RestController
public class HelloController {
    @Autowired
    Car car;
    @RequestMapping("/car")
    public Car car(){
        return car;
    }
    @RequestMapping("/hello")
    public String handle01(){
        return "Hello,Spring Boot 2!"+"你好";
    }
}

这里我写了个控制层,运行结果如下:

可以看出确实将properties文件内的内容封装了。


总结

以上就是SpringBoot的一些底层注解的讲解。

相关推荐
一只叫煤球的猫8 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9658 小时前
tcp/ip 中的多路复用
后端
bobz9658 小时前
tls ingress 简单记录
后端
皮皮林5519 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友9 小时前
什么是OpenSSL
后端·安全·程序员
bobz96510 小时前
mcp 直接操作浏览器
后端
前端小张同学12 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook12 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康13 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在13 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net