- 浏览: 106754 次
- 性别:
- 来自: 北京
文章分类
最新评论
最近有个项目场景,多垂类支持,大体业务流程相同,只是一些业务规则的校验参数不同。解决思路是将业务参数作为类的属性,然后创建垂类数量个实例,去处理不同垂类的业务。
看了spring ioc部分的代码,个人感觉在spring完成bean创建的过程后,做一个类实现ApplicationContextAware接口,然后克隆多个需要的BeanDefinition,附不同的业务参数属性值的方式比较讨巧。新增加的BeanDefinition会在getBean的过程中,由spring创建。
下面分两部分介绍:
1、动态创建bean的代码实现
2、spring的ioc源码解读,这部分放到另外一篇博客http://mazhen2010.iteye.com/blog/2283773
<spring.version>4.0.6.RELEASE</spring.version>
【动态创建bean的代码实现】
1、创建一个实现ApplicationContextAware接口的类,然后获取DefaultListableBeanFactory
2、定义注解,以找到需要克隆的BeaDefinition和需要赋值的属性
3、从垂类模板中获取需要动态创建的bean信息,然后注册BeanDefinition
4、定义一个Context继承AbstractServiceContext,实现运行时根据策略,选取所需的业务实例进行处理
5、在springContext.xml中声明TemplateBeanFactory
<bean class="com.baidu.nuomi.tpl.spring.TemplateBeanFactory"/>
TemplateBeanFactory的完整代码,包括模板变化时的刷新
看了spring ioc部分的代码,个人感觉在spring完成bean创建的过程后,做一个类实现ApplicationContextAware接口,然后克隆多个需要的BeanDefinition,附不同的业务参数属性值的方式比较讨巧。新增加的BeanDefinition会在getBean的过程中,由spring创建。
下面分两部分介绍:
1、动态创建bean的代码实现
2、spring的ioc源码解读,这部分放到另外一篇博客http://mazhen2010.iteye.com/blog/2283773
<spring.version>4.0.6.RELEASE</spring.version>
【动态创建bean的代码实现】
1、创建一个实现ApplicationContextAware接口的类,然后获取DefaultListableBeanFactory
private void setSpringFactory(ApplicationContext applicationContext) { if (applicationContext instanceof AbstractRefreshableApplicationContext) { // suit both XmlWebApplicationContext and ClassPathXmlApplicationContext AbstractRefreshableApplicationContext springContext = (AbstractRefreshableApplicationContext) applicationContext; if (!(springContext.getBeanFactory() instanceof DefaultListableBeanFactory)) { LOGGER.error("No suitable bean factory! The current factory class is {}", springContext.getBeanFactory().getClass()); } springFactory = (DefaultListableBeanFactory) springContext.getBeanFactory(); } else if (applicationContext instanceof GenericApplicationContext) { // suit GenericApplicationContext GenericApplicationContext springContext = (GenericApplicationContext) applicationContext; springFactory = springContext.getDefaultListableBeanFactory(); } else { LOGGER.error("No suitable application context! The current context class is {}", applicationContext.getClass()); } }
2、定义注解,以找到需要克隆的BeaDefinition和需要赋值的属性
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface TemplateService { //服务名称 String serviceName(); //服务实现名称 String value() default ""; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TemplateBizParam { } @TemplateService(serviceName = "demoService", value = "demoServiceImpl") public class DemoServiceImpl extends AbstractServiceImpl implements DemoService { @TemplateBizParam private String noVisitDays; @Override public void doDemo(Long poiId) { StringBuilder builder = new StringBuilder("doDemo").append("//").append("poiId:").append(poiId); builder.append("//").append(noVisitDays).append("//").append(getExtendFields()).append("//"); builder.append("abc:").append(getExtendField("abc")); System.out.println(builder.toString()); } @Override public void doDemos(List<Long> poiIds) { System.out.println("poiIds" + poiIds + "; noVisitDays:" + noVisitDays); } }
3、从垂类模板中获取需要动态创建的bean信息,然后注册BeanDefinition
private void registerBeanDefinition(String templateId, ServiceEntity serviceEntity) { try { if (springFactory.containsBeanDefinition(serviceEntity.getImplName())) { //step1: 注入多个实例 String beanKey = generateTemplateBeanName(templateId, serviceEntity.getServiceName()); BeanDefinition beanDefinition = springFactory.getBeanDefinition(serviceEntity.getImplName()); String className = beanDefinition.getBeanClassName(); Class c = null; try { c = Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); } BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(className); beanDefinitionBuilder.getBeanDefinition().setAttribute("id", beanKey); springFactory.registerBeanDefinition( beanKey, beanDefinitionBuilder.getBeanDefinition()); LOGGER.info("Register bean definition successfully. beanName:{}, implName:{}", generateTemplateBeanName(templateId, serviceEntity.getServiceName()), serviceEntity.getImplName()); //step2: 为实例自动化注入属性 Object bean = springFactory.getBean(beanKey, c); injectParamVaules(bean, c, serviceEntity); } } catch (NoSuchBeanDefinitionException ex) { LOGGER.info("No bean definition in spring factory. implName:{}", serviceEntity.getImplName()); } catch (BeanDefinitionStoreException ex) { LOGGER.info("Register bean definition wrong. beanName:{}, implName:{}", generateTemplateBeanName(templateId, serviceEntity.getServiceName()), serviceEntity.getImplName()); } } private <T> void injectParamVaules(Object bean, Class<T> requiredType, ServiceEntity serviceEntity) { if (requiredType.isAnnotationPresent(TemplateService.class)) { Field[] fields = requiredType.getDeclaredFields(); //获取类的所有属性 for (Field field : fields) { // 注入业务参数 if (field.isAnnotationPresent(TemplateBizParam.class)) { field.setAccessible(true); try { if ((serviceEntity.getBizParamMap() != null) && (serviceEntity.getBizParamMap().containsKey(field.getName()))) { field.set(bean, serviceEntity.getBizParamMap().get(field.getName())); LOGGER.info("inject biz param value successfully, paramName = {}, value = {}", field.getName(), serviceEntity.getBizParamMap().get(field.getName())); } } catch (IllegalAccessException e) { LOGGER.error("inject biz param failed. {}", e.getMessage()); e.printStackTrace(); } } } Class<AbstractService> superClass = getSuperClass(requiredType); if(superClass != null) { Field[] superFields = superClass.getDeclaredFields(); //获取类的所有属性 for (Field field : superFields) { // 注入扩展字段 if (field.isAnnotationPresent(TemplateExtendFields.class)) { field.setAccessible(true); try { if(serviceEntity.getExtendFields() != null){ field.set(bean, serviceEntity.getExtendFields()); LOGGER.info("inject extend fields successfully, extendFields = {}", serviceEntity.getExtendFields()); } } catch (IllegalAccessException e) { LOGGER.error("inject extend fields failed. {}", e.getMessage()); e.printStackTrace(); } } } } } }
4、定义一个Context继承AbstractServiceContext,实现运行时根据策略,选取所需的业务实例进行处理
@Service("demoService") public class DemoServiceContext extends AbstractServiceContext implements DemoService { @Override public void doDemo(Long poiId) { getServiceImpl(poiId, DemoService.class).doDemo(poiId); } } /** * 服务上下文抽象类,负责具体服务实现类的策略选择和扩展字段传递. * User: mazhen01 * Date: 2016/3/3 * Time: 10:14 */ public abstract class AbstractServiceContext { @Resource private TemplateBeanFactory templateBeanFactory; @Autowired public TemplateFunction templateFunction; // 当前线程使用的beanName private ThreadLocal<String> currentTemplateBeanName = new ThreadLocal<String>(); private static final Logger LOGGER = LoggerFactory.getLogger(AbstractServiceContext.class); /** * 根据POI所属行业,获取服务实例 * * @param poiId poiId * @param clazz 服务接口 * @param <T> 实例类型 * @return * @throws AnnotationException * @throws BeansException */ protected <T> T getServiceImpl(Long poiId, Class<T> clazz) throws AnnotationException, BeansException { String serviceName = getServiceName(); String templateId = templateFunction.getTemplateId(poiId, serviceName); if (templateId == null) { LOGGER.error("templateId is null. No templateId id configured for poiId = {}.", poiId); throw new TemplateException("templateId is null, can not find templateId."); } currentTemplateBeanName.set(TemplateBeanFactory.generateTemplateBeanName(templateId, serviceName)); return templateBeanFactory.getBean(TemplateBeanFactory.generateTemplateBeanName(templateId, serviceName), clazz); } protected <T> T getServiceImpl(List<Long> poiIds, Class<T> clazz) throws AnnotationException, BeansException { if (CollectionUtils.isEmpty(poiIds)) { LOGGER.error("poiIds List is null"); throw new TemplateException("poiIds is null."); } Long poiId = poiIds.get(0); return getServiceImpl(poiId, clazz); } /** * 根据beanName,获取服务实例 * * @param templateBeanName beanName * @param clazz 服务接口 * @param <T> 实例类型 * @return * @throws AnnotationException * @throws BeansException */ protected <T> T getServiceImpl(String templateBeanName, Class<T> clazz) throws AnnotationException, BeansException { return templateBeanFactory.getBean(templateBeanName, clazz); } /** * 根据POI所属行业,获取服务实例的扩展字段列表 * * @param poiId * @return */ public List<String> getExtendFields(Long poiId) { AbstractServiceImpl abstractService = getServiceImpl(poiId, AbstractServiceImpl.class); if (abstractService == null || CollectionUtils.isEmpty(abstractService.getExtendFields())) { Lists.newArrayList(); } return abstractService.getExtendFields(); } /** * 根据POI所属行业,设置服务实例所需要的扩展字段的具体值 * * @param poiId poiId * @param request 用户请求 */ public void setExtendField(Long poiId, HttpServletRequest request) { if (request == null) { return; } AbstractServiceImpl abstractService = getServiceImpl(poiId, AbstractServiceImpl.class); if (abstractService == null || CollectionUtils.isEmpty(abstractService.getExtendFields())) { return; } for (String field : abstractService.getExtendFields()) { setExtendField(field, request.getAttribute(field)); } } /** * 对扩展字段进行赋值 * * @param field 字段名 * @param value 值 */ public void setExtendField(String field, Object value) { if (currentTemplateBeanName == null || StringUtils.isEmpty(currentTemplateBeanName.get())) { return; } AbstractServiceImpl abstractService = getServiceImpl(currentTemplateBeanName.get(), AbstractServiceImpl.class); abstractService.getExtendFieldMap().put(field, value); } protected String getServiceName() throws AnnotationException { Class serviceClass = this.getClass(); if (serviceClass.isAnnotationPresent(Service.class)) { Service service = this.getClass().getAnnotation(Service.class); if (service != null) { return service.value(); } throwException("Has no Service annotation."); } if (serviceClass.isAnnotationPresent(Component.class)) { Component component = this.getClass().getAnnotation(Component.class); if (component != null) { return component.value(); } throwException("Has no Component annotation."); } LOGGER.error("Has no annotation."); return null; } /** * 根据品类模板,对poiId进行分组 * * @param poiIds * @return */ public Map<Long, List<Long>> groupPoiIds(List<Long> poiIds) { Map<Long, List<Long>> map = null; map = templateFunction.groupPoiIds(poiIds); return map; } private void throwException(String message) throws AnnotationException { message = this.getClass() + "||" + message; LOGGER.error(message); throw new AnnotationException(message); } }
5、在springContext.xml中声明TemplateBeanFactory
<bean class="com.baidu.nuomi.tpl.spring.TemplateBeanFactory"/>
TemplateBeanFactory的完整代码,包括模板变化时的刷新
/** * Bean工厂,创建在模板中定义的服务实例,填充业务参数和扩展字段 * 定时刷新,如发现模板定义中的服务有变化,则刷新spring上下文中的实例. * User: mazhen01 * Date: 2016/3/1 * Time: 16:46 */ public class TemplateBeanFactory implements ApplicationContextAware { private DefaultListableBeanFactory springFactory; private static final Logger LOGGER = LoggerFactory.getLogger(TemplateBeanFactory.class); @Autowired TemplateFunction templateFunction; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { setSpringFactory(applicationContext); templateFunction.init(); loadTemplateBeanDefinitions(templateFunction.getAllTemplateEntity()); } /** * 刷新模板bean */ public void refreshTemplateBeans(List<TemplateEntity> changedTemplates) { LOGGER.info("Refresh changed template beans start."); if(CollectionUtils.isEmpty(changedTemplates)){ LOGGER.info("no template beans is changed"); return; } destroyTemplateBeans(changedTemplates); loadTemplateBeanDefinitions(changedTemplates); LOGGER.info("Refresh changed template beans end."); } /** * 根据应用使用的不同applicationContext,获取BeanFactory * * @param applicationContext 应用使用的applicationContext */ private void setSpringFactory(ApplicationContext applicationContext) { if (applicationContext instanceof AbstractRefreshableApplicationContext) { // suit both XmlWebApplicationContext and ClassPathXmlApplicationContext AbstractRefreshableApplicationContext springContext = (AbstractRefreshableApplicationContext) applicationContext; if (!(springContext.getBeanFactory() instanceof DefaultListableBeanFactory)) { LOGGER.error("No suitable bean factory! The current factory class is {}", springContext.getBeanFactory().getClass()); } springFactory = (DefaultListableBeanFactory) springContext.getBeanFactory(); } else if (applicationContext instanceof GenericApplicationContext) { // suit GenericApplicationContext GenericApplicationContext springContext = (GenericApplicationContext) applicationContext; springFactory = springContext.getDefaultListableBeanFactory(); } else { LOGGER.error("No suitable application context! The current context class is {}", applicationContext.getClass()); } } /** * 将模板中定义的service,填充业务参数和扩展字段,添加到BeanFactory的definition中 */ private void loadTemplateBeanDefinitions(List<TemplateEntity> templateEntityList) { if (CollectionUtils.isEmpty(templateEntityList)) { LOGGER.warn(""); return; } for (TemplateEntity templateEntity : templateEntityList) { if (templateEntity == null || CollectionUtils.isEmpty(templateEntity.getServiceList())) { continue; } Long templateId = templateEntity.getIndustryId(); for (ServiceEntity serviceEntity : templateEntity.getServiceList()) { registerBeanDefinition(templateId.toString(), serviceEntity); } } } /** * 根据service信息,创建BeanDefinition * * @param templateId 模板ID * @param serviceEntity service信息 */ private void registerBeanDefinition(String templateId, ServiceEntity serviceEntity) { try { if (springFactory.containsBeanDefinition(serviceEntity.getImplName())) { //step1: 注入多个实例 String beanKey = generateTemplateBeanName(templateId, serviceEntity.getServiceName()); BeanDefinition beanDefinition = springFactory.getBeanDefinition(serviceEntity.getImplName()); String className = beanDefinition.getBeanClassName(); Class c = null; try { c = Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); } BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(className); beanDefinitionBuilder.getBeanDefinition().setAttribute("id", beanKey); springFactory.registerBeanDefinition( beanKey, beanDefinitionBuilder.getBeanDefinition()); LOGGER.info("Register bean definition successfully. beanName:{}, implName:{}", generateTemplateBeanName(templateId, serviceEntity.getServiceName()), serviceEntity.getImplName()); //step2: 为实例自动化注入属性 Object bean = springFactory.getBean(beanKey, c); injectParamVaules(bean, c, serviceEntity); } } catch (NoSuchBeanDefinitionException ex) { LOGGER.info("No bean definition in spring factory. implName:{}", serviceEntity.getImplName()); } catch (BeanDefinitionStoreException ex) { LOGGER.info("Register bean definition wrong. beanName:{}, implName:{}", generateTemplateBeanName(templateId, serviceEntity.getServiceName()), serviceEntity.getImplName()); } } /** * 为bean实例注入业务参数和扩展字段 * * @param bean * @param requiredType * @param serviceEntity * @param <T> */ private <T> void injectParamVaules(Object bean, Class<T> requiredType, ServiceEntity serviceEntity) { if (requiredType.isAnnotationPresent(TemplateService.class)) { Field[] fields = requiredType.getDeclaredFields(); //获取类的所有属性 for (Field field : fields) { // 注入业务参数 if (field.isAnnotationPresent(TemplateBizParam.class)) { field.setAccessible(true); try { if ((serviceEntity.getBizParamMap() != null) && (serviceEntity.getBizParamMap().containsKey(field.getName()))) { field.set(bean, serviceEntity.getBizParamMap().get(field.getName())); LOGGER.info("inject biz param value successfully, paramName = {}, value = {}", field.getName(), serviceEntity.getBizParamMap().get(field.getName())); } } catch (IllegalAccessException e) { LOGGER.error("inject biz param failed. {}", e.getMessage()); e.printStackTrace(); } } } Class<AbstractService> superClass = getSuperClass(requiredType); if(superClass != null) { Field[] superFields = superClass.getDeclaredFields(); //获取类的所有属性 for (Field field : superFields) { // 注入扩展字段 if (field.isAnnotationPresent(TemplateExtendFields.class)) { field.setAccessible(true); try { if(serviceEntity.getExtendFields() != null){ field.set(bean, serviceEntity.getExtendFields()); LOGGER.info("inject extend fields successfully, extendFields = {}", serviceEntity.getExtendFields()); } } catch (IllegalAccessException e) { LOGGER.error("inject extend fields failed. {}", e.getMessage()); e.printStackTrace(); } } } } } } private Class<AbstractService> getSuperClass(Class clazz) { if (!AbstractService.class.isAssignableFrom(clazz)) { LOGGER.info("super class is null"); return null; } Class<? extends AbstractService> superClass = clazz.getSuperclass(); if (AbstractService.class != superClass) { superClass = getSuperClass(superClass); } return (Class<AbstractService>) superClass; } /*** * 销毁模板bean */ private void destroyTemplateBeans(List<TemplateEntity> changedTemplates) { if (CollectionUtils.isEmpty(changedTemplates)) { LOGGER.warn(""); return; } for (TemplateEntity templateEntity : changedTemplates) { if (templateEntity == null || CollectionUtils.isEmpty(templateEntity.getServiceList())) { continue; } String templateId = templateEntity.getIndustryId().toString(); for (ServiceEntity serviceEntity : templateEntity.getServiceList()) { if (springFactory.containsSingleton(generateTemplateBeanName(templateId, serviceEntity.getServiceName()))) { // springFactory.destroySingleton(generateTemplateBeanName(templateId, serviceEntity.getServiceName())); 不需要显示的destroy方法,removeBeanDefinition中已调用此方法了 springFactory.removeBeanDefinition(generateTemplateBeanName(templateId, serviceEntity.getServiceName())); LOGGER.info("destroy template beans successfully for beanName = {}", generateTemplateBeanName(templateId, serviceEntity.getServiceName())); } } } } /** * 从springFactory中获取bean * * @param name bean名称 * @param requiredType bean类型 * @param <T> * @return * @throws BeansException */ public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return springFactory.getBean(name, requiredType); } ; /** * 生成模板service实例名称 * * @param templateId 模板ID * @param serviceName service名称 * @return */ public static final String generateTemplateBeanName(String templateId, String serviceName) { StringBuilder builder = new StringBuilder(serviceName); builder.append("_"); builder.append(templateId); return builder.toString(); } }
相关推荐
spring动态向容器中添加bean和删除指定bean,不需要重启应用
#### 创建BeanDefinition 接下来,使用`BeanDefinitionBuilder`来构建Bean的定义。`BeanDefinitionBuilder`提供了简洁的API来定义一个Bean的所有属性和行为,包括它的类型、依赖注入的属性等。在这个例子中,我们...
Spring Boot动态创建Bean示例代码详解 Spring Boot框架中提供了多种方式来创建Bean,今天我们就来学习其中的一种,即动态创建Bean。动态创建Bean可以根据特定的条件来决定是否创建Bean,这在实际开发中非常有用。 ...
Spring动态加载bean后调用实现方法解析 在 Spring 框架中,动态加载 bean 是一个非常实用的功能,特别是在我们需要在不改变原有程序结构的基础上添加新的 bean 的时候。通过使用 Spring 的 ...
本文将详细探讨如何在Spring Boot项目中基于Spring Kafka动态创建Kafka消费者。 首先,了解Kafka基本概念:Kafka是一种分布式流处理平台,用于构建实时数据管道和流应用程序。它提供了高吞吐量、低延迟的消息传递,...
在 Spring 框架中,动态注册 Bean 是一个非常重要的功能,它允许开发者在应用程序运行时动态添加或删除 Bean,从而提高应用程序的灵活性和可维护性。下面我们将详细介绍 Spring 之动态注册 Bean 的实现方法。 动态...
在使用Spring Boot开发JSP应用时,动态创建Bean是一个高级功能,它允许在运行时根据特定条件或配置创建和管理Bean,而不是在启动时静态定义。 Spring框架提供了多种方式来实现动态创建Bean,其中使用注解导入是一种...
在Spring容器初始化时,它会根据配置加载Bean的定义,并根据需要创建Bean实例。Bean的生命周期大致分为以下几个阶段:构造、初始化、正常使用、销毁。如果一个Bean被创建了两次,那么可能是在构造或初始化阶段出现了...
总的来说,"spring IOC反射装载bean"是Spring框架的基础,它使得开发者可以专注于业务逻辑,而不必关心对象的创建和依赖关系的管理。通过XML配置或注解,Spring能够灵活地控制Bean的生命周期,从而提高代码的可测试...
Spring 中如何动态注入 Bean 实例教程 Spring 框架中提供了多种方式来注入 Bean 实例,但是在实际项目中,基于动态的方式来提取 Spring 管理的 Bean 是非常有价值的。本文将详细介绍动态注入 Bean 实例的方式和...
在创建Bean的过程中,Spring会使用DOM4J解析XML配置文件,DOM4J是一个强大的Java文档处理库,可以方便地读取、修改和操作XML文档。在Spring的配置文件中,我们定义了Bean的元数据,包括Bean的类名、属性、依赖关系等...
本篇文章将深入探讨Spring动态加载Bean的概念、实现方式以及其在实际开发中的应用。 首先,理解Bean的生命周期是至关重要的。在Spring中,Bean的生命周期包括实例化、初始化、正常服务和销毁等阶段。通常,Spring...
在Spring框架中,`@Bean`注解是一个关键的组件,用于声明一个方法将返回的对象作为Spring容器中的bean。在`@Bean`中定义`initMethod`属性,可以指定该bean初始化时需要调用的方法。当`initMethod`被设置为异步执行,...
1. **工厂方法**: 在某些情况下,我们可能需要自定义创建Bean实例的过程,这就是工厂方法的作用。通过定义`@Bean`注解的`factoryMethod`属性,我们可以指定一个静态或非静态方法来创建Bean,而不是使用默认的构造...
对于接口,Spring提供了`@Lookup`注解,可以在运行时动态创建Bean实例。这通常用于实现类的懒加载或者运行时的选择。 6. **使用`ApplicationContextAware`接口** 实现`ApplicationContextAware`接口,可以获取到`...
首先,我们来了解一下Spring容器如何创建Bean。当Spring容器加载了配置文件(如XML或Java配置)后,它会根据配置信息实例化Bean。Bean的创建有两种方式:默认构造器创建和工厂方法创建。默认构造器创建是通过无参数...
在Java开发中,代理模式...当Spring容器创建一个Bean时,如果该Bean被标记为可代理的,Spring会使用JDK或CGLIB创建一个代理Bean,然后将这个代理Bean传递给BeanPostProcessor的`postProcessBeforeInitialization()`和`...
静态工厂方法与实例工厂方法类似,区别在于它不依赖于工厂类的实例,而是直接调用工厂类的静态方法来创建Bean。配置如下: ```xml <bean id="exampleBean" factory-class=...
在"Quartz(二)整合Spring容器中bean及动态调度任务"这个主题中,我们将探讨如何在Spring容器中配置和使用Quartz,以及如何动态地调度任务。首先,我们需要在Spring的配置文件中声明Quartz的相关bean,如`...