一句话概括就是 @Configuration
中所有带 @Bean
注解的办法都会被动静代理,因而调用该办法返回的都是同一个实例。
了解:调用 @Configuration
类中的 @Bean 注解的办法,返回的是同一个示例;而调用 @Component
类中的 @Bean
注解的办法,返回的是一个新的实例。
留神:下面说的调用,而不是从 spring 容器中获取! 见最上面的示例 1 及 示例 2
上面看看实现的细节。
@Configuration 注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {String value() default "";
}
从定义来看,@Configuration
注解实质上还是 @Component
,因而 <context:component-scan/>
或者 @ComponentScan
都能解决@Configuration
注解的类。
@Configuration
标记的类必须合乎上面的要求:
- 配置类必须以类的模式提供(不能是工厂办法返回的实例),容许通过生成子类在运行时加强(cglib 动静代理)。
- 配置类不能是 final 类(没法动静代理)。
- 配置注解通常为了通过
@Bean
注解生成 Spring 容器治理的类, - 配置类必须是非本地的(即不能在办法中申明,不能是 private)。
- 任何嵌套配置类都必须申明为 static。
@Bean
办法可能不会反过来创立进一步的配置类(也就是返回的 bean 如果带有@Configuration
,也不会被非凡解决,只会作为一般的 bean)。
@Bean 注解办法执行策略
举荐一个开源收费的 Spring Boot 最全教程:
https://github.com/javastacks/spring-boot-best-practice
先给一个简略的示例代码:
@Configuration
public class MyBeanConfig {
@Bean
public Country country(){return new Country();
}
@Bean
public UserInfo userInfo(){return new UserInfo(country());
}
}
置信大多数人第一次看到下面 userInfo()
中调用 country()
时,会认为这里的 Country 和下面 @Bean
办法返回的 Country 可能不是同一个对象,因而可能会通过上面的形式来代替这种形式:
@Autowired
private Country country;
实际上不须要这么做(前面会给出须要这样做的场景),间接调用 country()
办法返回的是同一个实例。
@Component 注解
@Component
注解并没有通过 cglib 来代理@Bean
办法的调用,因而像上面这样配置时,就是两个不同的 country
。
@Component
public class MyBeanConfig {
@Bean
public Country country(){return new Country();
}
@Bean
public UserInfo userInfo(){return new UserInfo(country());
}
}
有些非凡状况下,咱们不心愿 MyBeanConfig
被代理(代理后会变成WebMvcConfig$$EnhancerBySpringCGLIB$$8bef3235293
)时,就得用 @Component
,这种状况下,下面的写法就须要改成上面这样:
@Component
public class MyBeanConfig {
@Autowired
private Country country;
@Bean
public Country country(){return new Country();
}
@Bean
public UserInfo userInfo(){return new UserInfo(country);
}
}
这种形式能够保障应用的同一个 Country 实例。
示例 1:调用 @Configuration 类中的 @Bean 注解的办法,返回的是同一个示例
第一个 bean 类
package com.xl.test.logtest.utils;
public class Child {
private String name = "the child";
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
第二个 bean 类
package com.xl.test.logtest.utils;
public class Woman {
private String name = "the woman";
private Child child;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Child getChild() {return child;}
public void setChild(Child child) {this.child = child;}
}
@Configuration
类
package com.xl.test.logtest.utils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
//@Component
public class Human {
@Bean
public Woman getWomanBean() {Woman woman = new Woman();
woman.setChild(getChildBean()); // 间接调用 @Bean 注解的办法办法 getChildBean()
return woman;
}
@Bean
public Child getChildBean() {return new Child();
}
}
测试类 I
本测试类为一个配置类,这样启动我的项目是就能够看到测试成果,更加快捷;也能够应用其余形式测试见上面的测试类 II
package com.xl.test.logtest.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Man {
@Autowired
public Man(Woman wn, Child child) {System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(wn.getChild() == child ? "是同一个对象":"不是同一个对象");
}
}
启动我的项目,查看输入后果:
测试类 II
package com.xl.test.logtest.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xl.test.logtest.utils.Child;
import com.xl.test.logtest.utils.Woman;
@RestController
public class LogTestController {
@Autowired
Woman woman ;
@Autowired
Child child;
@GetMapping("/log")
public String log() {return woman.getChild() == child ? "是同一个对象":"不是同一个对象";
}
}
浏览器拜访我的项目,查看后果;输出localhost:8080/log
示例 2:调用 @Component 类中的 @Bean 注解的办法,返回的是一个新的实例。
测试代码,只须要将 @Configuration
改为 @Component
即可!其余的均不变
package com.xl.test.logtest.utils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//@Configuration
@Component
public class Human {
@Bean
public Woman getWomanBean() {Woman woman = new Woman();
woman.setChild(getChildBean()); // 间接调用 @Bean 注解的办法办法 getChildBean()
return woman;
}
@Bean
public Child getChildBean() {return new Child();
}
}
测试 :
控制台和浏览器展现,均合乎预期!
原文:blog.csdn.net/qq_29025955/article/details/128818957
近期热文举荐:
1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)
2. 劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!