@Configuration注解

这里写目录标题

      • @Configuration基础用法
      • 添加 @Configuration 注解的意义?
      • @Configuration和@Component的区别
      • 原理分析
      • Full模式和Lite模式

@Configuration基础用法

先来看段代码,一般来说,我们会在配置上添加 @Configuration 注解,但是,如果不添加,似乎也能运行,类似下面这样:

public class JavaConfig {
    @Bean
    public User user() {
        User user = new User();
        user.setDog(dog());
        return user;
    }
}

添加 @Configuration 注解的意义?

既然加不加@Configuration注解都可以,那注解的意义在哪里呢:
假设有一个 User,养了一只 Dog,现在要将两者都注册到 Spring 容器中去:

public class User {
    private Dog dog;
    public Dog getDog() {
        return dog;
    }
    public void setDog(Dog dog) {
        this.dog = dog;
    }
}
public class JavaConfig {
    @Bean("dog")
    public Dog dog() {
        return new Dog();
    }
    @Bean
    public User user() {
        User user = new User();
        user.setDog(dog());
        return user;
    }
}

注意,这个类上没有@Configuration 注解
最终运行结果如下:
@Configuration注解_第1张图片
从这张图可以看出来,当user 中调用 dog 方法的时候,实际上该方法又执行了一次,这就导致最终注册到 Spring 容器中的 Dog 和 User 所使用的 Dog 并非同一个
发生上面这个问题的原因,在于配置类上面没有注解,现在加上注解之后,再来看运行结果:
@Configuration注解_第2张图片
从这里可以看出来,dog0 方法只执行了一次,并 user 中所使用的 dog 和注册到 Spring 容器中的 dog 是同一个。
此时我们就能大致总结出来 @Configuration 注解的作用了:

如果配置类上添加了@Configuration 注解的话,那么在配置类内部方法调用的时候,例如上面的 ser 中调用 dog 方法的时候,并不会直接调用 dog 方法,而是先去 Spring 容器中查找是否存在 dog 对象,如果存在,则直接拿来使用,如果Spring 容器中不存在 dog 对象,才会调用 dog 方法,调用的时候,不仅 user 自己使用,也会 Spring 容器注册dog 对象。这就是@Configuration 注解所体现的意义

当然,对于没有添加 @Configuration 注解的配置类来说,其实也有另外一种方式实现上面的效果,
@Configuration注解_第3张图片
对于上面这个案例来说,user 方法中,直接添加了 dog 对象作为参数,user 方法最终是被 Spring 容器调用的,Spring 容器在调用 user 方法的时候,会监测到该方法需要一个 dog 对象作为参数,那么 Spring 容器就会自动去容器中查找是否存在个Dog 对象,如果存在,就注入进来直接使用,这样,最终 user 中的 dog 和 Spring 容器中的 dog 是就是同一个。

@Configuration和@Component的区别

一般来说,我们在配置类上添加的都是 @Configuration 注解,很少添加@Component 注解。
配置类上添加 @Component 注解的效果和不添加 @Configuration 的效果是一致的。
即如果配置类上添加的是 @Component 注解的话,那么在配置类内部发生方法调用的时候,那么方法就会被直接执行,而不会去 Spring 容器中查找.

原理分析

那么这个是如何实现的? 实际上,就是 AOP!
具体来说,最终注册到 Spring 容器中的 JavaConfig 配置类,并不是现在的 JavaConfig,而是一个代理对象:
@Configuration注解_第4张图片
那我们可以猜测,这个代理对象中,为每一个方法都生成了代理方法,在代理方法中,首先会去 Spring 容器中查找 Bean,如果 Spring 容器中不存在,才会调用目标对象。一段伪代码:

public class ProxyJavaConfig extends JavaConfig{
	JavaConfig javaconfig=new JavaConfig();
	BeanFactory bf = xxxx;
	@Override
	User user(){
		User u = bf.getBean(User.class);
		if(u==nul1){//spring 容器中没有找到 User 对象
			u = javaconfig.user();
		return u;
	}
	@override
	Dog dog(){
		Dog d = bf.getBean(Dog.class);
		if(d==null){
			d = javaconfig.dog();
		}
		return d;
	}

所以,我们也可以进一步总结,被 @Confiouration 所标的配置类,如果生成了代理对象,那么意味着被 @Bean 注解标记的方法最终都是要生成代理方法的,所以被 @Bean 注解标记的方法就不能是 private,不能是 final,当然配置类本身也不能是 final.

Full模式和Lite模式

官方文档:https://docs.spring.io/spring-framework/reference/core/beans/java/basic-concepts.html
Lite 模式分为很多种情况,但是把握住一个核心的点: Fu 模式最终是要生车代理对象的,而 Lite 模式是不生成代理对象的。

首先,在使用 @Configuration 注解的情况下,也可以使之成为 Lite 模式,只要加proxyBeanMethods = false

@Configuration(proxyBeanMethods = false)
public final class JavaConfig {

}

@Configuration注解_第5张图片
总结
@Configuration注解_第6张图片

你可能感兴趣的:(1024程序员节)