最近有个项目场景,多垂类支持,大体业务流程相同,只是一些业务规则的校验参数不同。解决思路是将业务参数作为类的属性,然后创建垂类数量个实例,去处理不同垂类的业务。
看了spring ioc部分的代码,个人感觉在spring完成bean创建的过程后,做一个类实现ApplicationContextAware接口,然后克隆多个需要的BeanDefinition,附不同的业务参数属性值的方式比较讨巧。新增加的BeanDefinition会在getBean的过程中,由spring创建。
下面分两部分介绍:
1、动态创建bean的代码实现
2、spring的ioc源码解读,这部分放到另外一篇博客[url]http://mazhen2010.iteye.com/blog/2283773[/url]
<spring.version>4.0.6.RELEASE</spring.version>
【动态创建bean的代码实现】
1、创建一个实现ApplicationContextAware接口的类,然后获取DefaultListableBeanFactory
2、定义注解,以找到需要克隆的BeaDefinition和需要赋值的属性
3、从垂类模板中获取需要动态创建的bean信息,然后注册BeanDefinition
看了spring ioc部分的代码,个人感觉在spring完成bean创建的过程后,做一个类实现ApplicationContextAware接口,然后克隆多个需要的BeanDefinition,附不同的业务参数属性值的方式比较讨巧。新增加的BeanDefinition会在getBean的过程中,由spring创建。
下面分两部分介绍:
1、动态创建bean的代码实现
2、spring的ioc源码解读,这部分放到另外一篇博客[url]http://mazhen2010.iteye.com/blog/2283773[/url]
<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