@Configuration注解
@Configuration这个注解可以加在类上,让这个类的功能等同于一个bean xml配置文件。
@Configuration
public class TestBean{
}
效果等同于
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
</beans>
@Configuration 使用步骤:
- 在类上使用 @Configuration 注解
- 通过 AnnotationConfigApplicationContext 容器来加载 @Configuration 注解修饰的类
@Bean注解
用法:
这个注解类似于bean xml配置文件中的bean元素,用来在spring容器中注册一个bean。
@Bean注解用在方法上,表示通过方法来定义一个bean,默认将方法名称作为bean名称,将方法返回
值作为bean对象,注册到spring容器中。
@Bean
public User user1() {
return new User();
}
看一@Bean的源码:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
@Deprecated
Autowire autowire() default Autowire.NO;
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})说明这个注解可以用在方法和注解类型上面
每个参数含义:
- value和name是一样的,设置的时候,这2个参数只能选一个,原因是@AliasFor导致的
@AliasFor这个注解不清楚的可以看这个文章:(文章最后)
https://blog.csdn.net/whatname123/article/details/107721423
- value:字符串数组,第一个值作为bean的名称,其他值作为bean的别名
- autowire:这个参数上面标注了@Deprecated,表示已经过期了,不建议使用了
- autowireCandidate:是否作为其他对象注入时候的候选bean。有多个同类型的bean,在spring不知道选哪个的时候起作用。
- initMethod:bean初始化的方法,这个和生命周期有关,这里先不讲
- destroyMethod:bean销毁的方法,也是和生命周期相关的,先不讲
使用:
class User {
}
@Configuration
public class BeanConfig {
//bean名称为方法默认值:user1
@Bean
public User user1(){
return new User();
}
//bean名称通过value指定了:userBean
@Bean("userBean")
public User user2(){
return new User();
}
//bean名称为:userBean1,2个别名:[testBean,myBean]
@Bean({"userBean1","testBean","myBean"})
public User user3(){
return new User();
}
}
输出(只截取了部分):
bean名称:beanConfig,别名:[],bean对象:com.test.annotation.BeanConfig$$EnhancerBySpringCGLIB$$9d7e12be@587c290d
bean名称:user1,别名:[],bean对象:com.test.annotation.User@4516af24
bean名称:userBean,别名:[],bean对象:com.test.annotation.User@4ae82894
bean名称:userBean1,别名:[myBean, testBean],bean对象:com.test.annotation.User@543788f3
去掉@Configuration会怎么样?
我们在BeanConfig类中去掉@Configuration
测试输出:
bean名称:beanConfig,别名:[],bean对象:com.test.annotation.BeanConfig@5e853265
bean名称:user1,别名:[],bean对象:com.test.annotation.User@67205a84
bean名称:userBean,别名:[],bean对象:com.test.annotation.User@7d0587f1
bean名称:userBean1,别名:[myBean, testBean],bean对象:com.test.annotation.User@5d76b067
对比上面的输出得出结论:
- 对比最后3行,可以看出:有没有@Configuration注解,@Bean都会起效,都会将@Bean修饰的方法作为bean注册到容器中
- 两个内容的第一行有点不一样,被@Configuration修饰的bean最后输出的时候带有
EnhancerBySpringCGLIB 的字样,而没有@Configuration注解的bean没有Cglib的字样;有EnhancerBySpringCGLIB 字样的说明这个bean被cglib处理过的,变成了一个代理对象。
关于cglib不清楚的请看这篇文章
https://blog.csdn.net/whatname123/article/details/115578231
@Configuration加不加到底区别在哪?
通常情况下,bean之间是有依赖关系的,我们来创建个有依赖关系的bean,通过这个案例你就可以看出根本的区别了。
案例一:(不加@Configuration)
package com.test.annotation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
class User {
}
class People{
private User user;
public People(User user) {
this.user = user;
}
@Override
public String toString() {
return "People{" +
"user=" + user +
'}';
}
}
public class BeanConfig {
@Bean
public User user1(){
System.out.println("调用了user创建方法");
return new User();
}
@Bean
public People people1(){
User user = this.user1();
System.out.println("调用了people创建方法一");
return new People(user);
}
@Bean
public People people2(){
User user = this.user1();
System.out.println("调用了people创建方法二");
return new People(user);
}
}
测试类还是用上面的测试类就行。
输出结果(截取部分):
调用了user创建方法
调用了user创建方法
调用了people创建方法一
调用了user创建方法
调用了people创建方法二
bean名称:user1,别名:[],bean对象:com.test.annotation.User@7d0587f1
bean名称:people1,别名:[],bean对象:People{user=com.test.annotation.User@5d76b067}
bean名称:people2,别名:[],bean对象:People{user=com.test.annotation.User@2a17b7b6}
加上@Configuration后
输出结果(截取部分):
调用了user创建方法
调用了people创建方法一
调用了people创建方法二
bean名称:user1,别名:[],bean对象:com.test.annotation.User@4ae82894
bean名称:people1,别名:[],bean对象:People{user=com.test.annotation.User@4ae82894}
bean名称:people2,别名:[],bean对象:People{user=com.test.annotation.User@4ae82894}
通过对比可以看出:
- 有@Configuration的,被@Bean修饰的方法都只被调用了一次。
- 有@Configuration的,所有的User都是同一个
这是为什么?
被@Configuration修饰的类,spring容器中会通过cglib给这个类创建一个代理,代理会拦截所有被@Bean 修饰的方法,默认情况(bean为单例)下确保这些方法只被调用一次,从而确保这些bean是同一个bean,即单例的
@Configuration修饰的类有cglib代理效果,默认添加的bean都为单例