详解底层注解
Ⅰ @Configuraion
我先定义一个简单的实体类 Book
。完成基本的 setter 方法和 toString 方法 。
在 Spring IOC 中,我们可以通过配置 xml 文件和注解两种方式来完成一个类的注入,也可以通过配置类生成对应的 Bean,我们在配置类中就会使用到 @Configuraion
注解。
【Java Web】 -> Spring 5 ->IOC 操作 -> Bean 管理 ->关于 IOC 的一切就在这里了
我们来看一下 Spring Boot 中的 @Configuraion
注解。
通过@Configuraion
和 @Bean
注解,我们可以创建出一个 Bean 的实例,默认组件的 id 就是方法名称,但是我们也可以重新定义自己想要的 id 名。
这样 id 就被改成了 bbb
,而不是方法名。
注意这时我们在容器中注册的组件默认就是单实例的,无论我们获取多少次,都会是同一个对象。
并且,我们的配置类本身也是一个组件,它是可以被获得的。
在 Spring Boot 2 中,还增加了一个属性 proxyBeanMethods
,可以看到这个属性是默认为 true 的。
这个属性表示是不是代理 bean 的方法。大家可以看我上面输出的 MyConfig 类的图。
MyConfig 类的对象其实是被 CGLIB 增强了的对象,简单来说就是它是一个代理对象。对于一个代理方法,Spring Boot 会检查它的方法所生成的对象,如果容器中已经存在了,就直接返回,不存在才进行创建。这就使得所注册的组件都是单例的。
现在我们将这个属性改成 false ,再来做一下测试。
测试结果如下
可以看到,生成的两个组件的对象并不相等,说明它们是两个不同的对象。并且,生成的 MyConfig 对象也是它本身的对象,并不是代理对象。
这就引出了 Spring Boot 的两个配置,全配置 Full 和 轻量级配置 Lite。
当 proxyBeanMethods
为 true
时,为全配置,此时配置类中每一个注册组件的方法,Spring Boot 都会在容器中查找组件,如果找到了就直接返回;
当 proxyBeanMethods
为 false
时,为轻量级配置,此时每一次调用配置类中的注册组件方法,都会产生一个新的对象。
通过这两种配置,可以解决 组件依赖 的问题。
比如这时我们再定义一个类,出版社 Press
。
然后我们让 Book
类依赖它。在 Book
类中增加相应的 Getter 和 Setter。
在 MyConfig
类中,对 Book
进行注入。
现在我们设置 proxyBeanMethods = true
,然后做一个测试。
可以看到,从容器中取得的 Book
类的对象,它的 press
和 直接从容器中取得的 press
是同一个。
而当我们将全配置改成轻量级配置之后,可以看到它们就不是同一个对象了。
当使用的是轻量级配置的时候,Spring Boot 不用每次都从容器中检查,而是直接创建,这样就比全配置每次都要检查一下快很多。
Ⅱ @Import
@Import
用于导入一个组件,可以写在容器中任意一个组件上。我们看一下它的源码,可以看到是一个 Class
类型的数组。
我们可以导入自己写的类的组件,也可以导入依赖的组件。
@Import
会调用它们的无参构造方法,给容器中自动创建出这两个类型的组件。
我们来做个简单的测试。由于 Book
类我们定义了两个生成 Bean 的方法,所以可以通过 getBeanNamesForType()
方法来获取容器中 Book
类对应的所有 id。
可以看到,除了我们定义的 bbb
之外,还有一个就是 Book
的全类名,这就是通过 @Import
注解导入的。下面还有一个 SLF4JBridgeHandler
类的全类名,显然这就是我们通过@Import
注解导入的另一个类。
Ⅲ @Conditional
@Conditional
是条件装配,意为满足 Conditional指定的条件,则进行组件注入。
比如我们在注入 Book
类的时候,需要注入 Press
类的对象。
但是,如果 Press
类没有对象被注册到容器中的话,Book
类依旧会被创建。
现在我们希望遵从这个依赖性,当 Press
不存在的时候,也不要对 Book
进行注册,要做到这一点我们就需要 @Conditional
注解。
Conditional 有许多扩展注解,我标记了两个做个例子, ConditionalOnBean
意味着有这个 Bean 时才进行组件注入,相对应的 ConditionalOnMissingBean
意味着没有这个 Bean 时才进行组件注入。
现在我们希望没有 Press
时就不注入 Book
,所以可以使用 ConditionalOnBean
。
可以看到,ConditionalOnBean
既可以根据 Bean 的类型,也可以根据 Bean 的名称(也就是 id)。我们根据名称来写。
我把 Press
的 Bean
注解注释掉了,以便我们验证效果。
可以看到,两个 Bean 都没有注册到容器中。
但是如果我们不加 Conditional 注解的话,再次做一个测试。
在 Press
没有被注册的情况下,Book
被成功地注册了。
Ⅳ @ImportResource
在上面我们使用的是配置类的方式类进行组件的注册,那么如果我们有一个 xml 配置文件,需要将里面的组件注册进来,就需要使用 @ImportResource
注解。
比如我现在写一个配置文件。
如果直接就在容器中查找这两个组件,必然是找不到的。
现在我们需要使用注解将这个配置文件导入,这样才能将其注册。
Ⅴ 配置绑定
我们有时会在 properties 文件中配置一些信息,比如数据库连接池之类的,然后 Java 来读取 properties 文件中的内容,并把它封装到 JavaBean 中,以供随时使用,这个过程就是配置绑定。
Spring Boot 为此也提供了很方便的方法。
我先定义一个 Bean,Car
,只有两个属性,一个是品牌brand
一个是价格price
。
完成基本的 Getter Setter 以及 toString 方法。
接着我们在 properties 配置文件中配置这个类的属性。
1. @ConfigurationProperties
我们并不需要写复杂的解析配置,只需要在对应的实体类上添加一个注解 @ConfigurationProperties
。
在这个注解中,我们需要写入一个属性 prefix
。
这个意思是我们这个类里的属性,和配置文件中哪个前缀下的所有属性一 一绑定。显然这里我们的前缀就是 mycar
。
为了使其生效,我们还需要将该类加到容器中,所以需要添加 @Component
注解。
要做测试,我们可以将 Car
类作为成员变量然后使用 Autowired
注解自动注入。
我们来测试一下这个响应,可以看到 Car 类被正确注入了我们配置文件中的数据。
2. @EnableConfigurationProperties
我们需要在配置类上写一个注解 EnableConfigurationProperties
,表示开启属性配置功能。既然我们要开启 Car
类的属性配置,所以就需要将它传进去。
这个注解除了会开启 Car
的配置绑定功能以外,还会将Car
这个组件自动注册到容器中。
使用这个方法我们就不需要在 Car
类上添加 @Component
注解了,毕竟我们有可能要配置的是第三方的类,我们是不能在别的类上添加代码的。
测试仍然是成功的。
Ⅵ 其他
@Bean
, @Component
, @Controller
, @Service
, @Repository
这些注解的用法都和 Spring 5 、 Spring MVC 中的一样,不再赘述。