/** * @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