Spring 关于Bean的注册方式
注册方式
- 通过配置XML注册
- 通过@Bean注册
- 通过Beanfactory注入
需要注册的Bean
/*** @Description: 自定义Bean
* @Author: Jonas
* @Date: 2020-06-01 22:52
*/
@Data
@Slf4j
publicclassMyBean{
private String name;
privateint age;
publicMyBean(String name, int age){
this.name = name;
this.age = age;
log.info("调用构造函数创建Bean,name={},age={}",name,age);
}
}
具体实现
1. 通过配置XML注册
applicationContext.xml
<beanid="myBean"class="com.jonas.config.bean.MyBean" ><constructor-argname="name"value="Jonas"/>
<constructor-argname="age"value="18"/>
</bean>
通过xml注入是Spring MVC中注入Bean常用的方式
现在项目中越来越多Spring Boot项目,而且配置XML的方式还是相对麻烦且难以维护,下面介绍的两种方式是现阶段中相对常见的方式
2. 通过@Bean注册
建造者模式创建Bean,这个类后面都会有提到
*** @Description: MyBeanBuilder 常见的建造者的方法
* @Author: Jonas
* @Date: 2020-06-0122:57
*/
publicclassMyBeanBuilder{
private String name;
privateint age;
public MyBeanBuilder withName(String name){
this.name = name;
returnthis;
}
public MyBeanBuilder withAge(int age){
this.age = age;
returnthis;
}
publicstatic MyBeanBuilder getInstance(){
returnnew MyBeanBuilder();
}
public MyBean build(){
returnnew MyBean(this.name,this.age);
}
}
通过@Bean创建Spring对象
/*** @Description: 使用@Bean创建并注入Spring
* @Author: Jonas
* @Date: 2020-06-01 23:09
*/
@Configuration
@Slf4j
publicclassAnnotationBean{
// 通过@Bean 调用构造函数,生成Bean,并将Bean交由BeanFactory管理
@Bean
public MyBean myBean(){
MyBean myBean = new MyBean("hello", 10);
log.info("向spring中注入成功 myBean");
return myBean;
}
// 通过@Bean 调用建造方法,生成Bean,本质和上面的方式差不多
@Bean
public MyBean myBean2(){
MyBean tom = MyBeanBuilder.getInstance()
.withName("Tom")
.withAge(22)
.build();
log.info("向spring中注入成功 myBean2");
return tom;
}
}
其实两者本质都是调用构造函数创建,只是后者是间接将参数传递给了构造函数
2. 通过Beanfactory动态注入
/*** @Description: 自定义Bean工厂
* @Author: Jonas
* @Date: 2020-06-01 22:50
*/
@Configuration
@Slf4j
publicclassMyBeanFactoryimplementsInitializingBean{
@Autowired
private ApplicationContext applicationContext; // Spring上下文
public MyBean createBean(String name,int age,String string){
log.info("调用工厂方法创建Bean");
log.info("输出第三个参数===>{}",string);
returnnew MyBean(name,age);
}
@Override
publicvoidafterPropertiesSet()throws Exception {
// 通过 DefaultListableBeanFactory 动态生成Bean
DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
log.info("==================进入方法====================");
// 动态创建10个类型为MyBean的不同的Bean对象
for (int i=0;i<10;i++) {
// 调用构造方法动态创建
// registerBean(applicationContext,"dynamic"+i,MyBean.class,"Bean"+i,10+i);
// 调用工厂方法动态创建Bean
registerBean(applicationContext,"dynamic"+i,
"myBeanFactory","createBean","Bean" + i,20+i, UUID.randomUUID().toString());
}
}
/**
* 调用Bean构造函数,注册Bean到上下文中
* @param applicationContext
* @param registerName
* @param clazz
* @param args
* @param <T>
* @return
*/
private <T> T registerBean(ApplicationContext applicationContext,
String registerName,
Class<T> clazz,
Object... args){
if(applicationContext.containsBean(registerName)) {
Object bean = applicationContext.getBean(registerName);
if (bean.getClass().isAssignableFrom(clazz)) {
return (T) bean;
} else {
thrownew RuntimeException("BeanName 重复 " + registerName);
}
}
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
for (Object arg : args) {
// 设置构造函数参数
beanDefinitionBuilder.addConstructorArgValue(arg);
}
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
beanFactory.registerBeanDefinition(registerName, beanDefinition);
return applicationContext.getBean(registerName, clazz);
}
/**
* 调用工厂方法,注册Bean到上下文中
* @param applicationContext
* @param registerName
* @param factoryBeanClazz
* @param factoryMethod
* @param args
* @param <T>
* @return
*/
private <T> T registerBean(ApplicationContext applicationContext,String registerName,
String factoryBeanClazz,String factoryMethod,Object... args){
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
// 建造一个父类的Bean,不可为其他类的子类
//.rootBeanDefinition()
// 建造一个子类的Bean,必须传递一个父类Bean的名称,不可为其他类的父类
// .childBeanDefinition()
// 建造一个标准的Bean
.genericBeanDefinition()
// 设置工厂方法和工厂类
.setFactoryMethodOnBean(factoryMethod, factoryBeanClazz);
for (Object arg: args) {
// 设置工厂方法参数
beanDefinitionBuilder.addConstructorArgValue(arg);
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
beanFactory.registerBeanDefinition(registerName,beanDefinition);
return (T) applicationContext.getBean(registerName);
}
}
调用工厂方法createBean动态创建10个不一样的Bean
调用构造方法动态创建10个不一样的Bean
总结
这三种是Bean常用的注册方式,第一种一般在SpringMVC中较为常见,但是感觉不是很方便。第二种是Spring Boot中常用的Bean注册方式,一般在配置类中经常需要手动加载Bean到Spring中去。第三种常常用于需要创建一批同类型的有一定重复命名规则的Bean,像前段时间对Swagger进行动态分组的时候就通过这个方式创建
附录
动态创建Swagger分组
EnableModuleTag.java
/*** @Description: 自动设置模块标记,便于日志模块的自动写入和swagger-ui的分组管理
* @author: Jonas
* @since: 2020/5/29 14:52
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public@interface EnableModuleTag {
String moduleName()default "SYSTEM";
}
SwaggerConfig.java
/*** @Description: swagger-ui配置,单体应用自动创建Swagger-ui分组
* @author: Jonas
* @since: 2020/5/30 22:53
*/
@Configuration
@EnableSwagger2
@Slf4j
publicclassSwaggerConfigimplementsInitializingBean{
private Set<String> groupName = new HashSet<>();
@Autowired
private ApplicationContext applicationContext;
@Bean
public Docket docket(){
// basePackage 需要扫描注解生成文档的路径
returnnew Docket(DocumentationType.SWAGGER_2)
// 分组名用aaa开头以便排在最前面
.groupName("默认分组(全部)")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.jonas.data"))
.paths(PathSelectors.any())
.build();
}
//基本信息,页面展示
private ApiInfo apiInfo(){
returnnew ApiInfoBuilder()
.title("SwaggerAPI")
.description("xxxx项目接口api")
//版本号
.version("1.0.0")
.build();
}
private Docket buildDocket(String groupName){
returnnew Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName(groupName)
.select()
.apis(method -> {
// 每个方法会进入这里进行判断并归类到不同分组,
// **请不要调换下面两段代码的顺序,在方法上的注解有优先级**
// 该方法上标注了模块名称
if (method.isAnnotatedWith(EnableModuleTag.class)) {
EnableModuleTag annotation = method.getHandlerMethod().getMethodAnnotation(EnableModuleTag.class);
if (annotation.moduleName() != null && annotation.moduleName().length() != 0) {
if (Arrays.asList(annotation.moduleName()).contains(groupName)) {
returntrue;
}
}
}
// 方法所在的类是否标注了?
EnableModuleTag annotationOnClass = method.getHandlerMethod().getBeanType().getAnnotation(EnableModuleTag.class);
if (annotationOnClass != null) {
if (annotationOnClass.moduleName() != null && annotationOnClass.moduleName().length() != 0) {
if (Arrays.asList(annotationOnClass.moduleName()).contains(groupName)) {
returntrue;
}
}
}
returnfalse;
})
.paths(PathSelectors.any())
.build();
}
/**
* 动态得创建Docket bean
* @throws Exception
*/
@Override
publicvoidafterPropertiesSet()throws Exception {
// ApiConstantVersion 里面定义的每个变量会成为一个docket
Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(EnableModuleTag.class);
for (Iterator<Object> iterator = beanMap.values().iterator(); iterator.hasNext();) {
Object bean = iterator.next();
EnableModuleTag annotation = bean.getClass().getAnnotation(EnableModuleTag.class);
// 获取模块名称,并放置到set中
String moduleName = annotation.moduleName();
groupName.add(moduleName);
// 动态注入bean
AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
// if (autowireCapableBeanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) autowireCapableBeanFactory;
// 要注意 "工厂名和方法名",意思是用这个bean的指定方法创建docket
// 获取驼峰命名
String registerName = CommonUtils.getHumnName("swagger_config_"+moduleName);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition()
.setFactoryMethodOnBean("buildDocket", "swaggerConfig")
.addConstructorArgValue(moduleName)
.getBeanDefinition();
capableBeanFactory.registerBeanDefinition(registerName, beanDefinition);
log.info("注册Bean:{} 到Spring中",registerName);
// }
}
}
}
用法:
controller加上注解标注
启动的时候自动注册不同的Bean到Spring中,从而实现根据模块自动创建不同分组,方便管理API
以上是 Spring 关于Bean的注册方式 的全部内容, 来源链接: utcz.com/a/21298.html