/** * @Description: 自定义Bean * @Author: Jonas * @Date: 2020-06-01 22:52 */
@Data
@Slf4j
public class MyBean {
private String name;
private int age;
public MyBean(String name, int age) {
this.name = name;
this.age = age;
log.info("调用构造函数建立Bean,name={},age={}",name,age);
}
}
复制代码
applicationContext.xmljava
<bean id="myBean" class="com.jonas.config.bean.MyBean" >
<constructor-arg name="name" value="Jonas"/>
<constructor-arg name="age" value="18"/>
</bean>
复制代码
经过xml注入是Spring MVC中注入Bean经常使用的方式spring
如今项目中愈来愈多Spring Boot项目,并且配置XML的方式仍是相对麻烦且难以维护,下面介绍的两种方式是现阶段中相对常见的方式api
建造者模式建立Bean,这个类后面都会有提到app
**
* @Description: MyBeanBuilder 常见的建造者的方法
* @Author: Jonas
* @Date: 2020-06-01 22:57
*/
public class MyBeanBuilder {
private String name;
private int age;
public MyBeanBuilder withName(String name) {
this.name = name;
return this;
}
public MyBeanBuilder withAge(int age) {
this.age = age;
return this;
}
public static MyBeanBuilder getInstance() {
return new MyBeanBuilder();
}
public MyBean build() {
return new MyBean(this.name,this.age);
}
}
复制代码
经过@Bean建立Spring对象dom
/** * @Description: 使用@Bean建立并注入Spring * @Author: Jonas * @Date: 2020-06-01 23:09 */
@Configuration
@Slf4j
public class AnnotationBean {
// 经过@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;
}
}
复制代码
其实二者本质都是调用构造函数建立,只是后者是间接将参数传递给了构造函数 ide
/** * @Description: 自定义Bean工厂 * @Author: Jonas * @Date: 2020-06-01 22:50 */
@Configuration
@Slf4j
public class MyBeanFactory implements InitializingBean {
@Autowired
private ApplicationContext applicationContext; // Spring上下文
public MyBean createBean(String name,int age,String string) {
log.info("调用工厂方法建立Bean");
log.info("输出第三个参数===>{}",string);
return new MyBean(name,age);
}
@Override
public void afterPropertiesSet() 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 {
throw new 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 ui
这三种是Bean经常使用的注册方式,第一种通常在SpringMVC中较为常见,可是感受不是很方便。第二种是Spring Boot中经常使用的Bean注册方式,通常在配置类中常常须要手动加载Bean到Spring中去。第三种经常用于须要建立一批同类型的有必定重复命名规则的Bean,像前段时间对Swagger进行动态分组的时候就经过这个方式建立this
动态建立Swagger分组spa
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
public class SwaggerConfig implements InitializingBean {
private Set<String> groupName = new HashSet<>();
@Autowired
private ApplicationContext applicationContext;
@Bean
public Docket docket() {
// basePackage 须要扫描注解生成文档的路径
return new Docket(DocumentationType.SWAGGER_2)
// 分组名用aaa开头以便排在最前面
.groupName("默认分组(所有)")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.jonas.data"))
.paths(PathSelectors.any())
.build();
}
//基本信息,页面展现
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SwaggerAPI")
.description("xxxx项目接口api")
//版本号
.version("1.0.0")
.build();
}
private Docket buildDocket(String groupName) {
return new 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)) {
return true;
}
}
}
// 方法所在的类是否标注了?
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)) {
return true;
}
}
}
return false;
})
.paths(PathSelectors.any())
.build();
}
/** * 动态得建立Docket bean * @throws Exception */
@Override
public void afterPropertiesSet() 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