阅读对象##

搭框架人员,或者其他感兴趣的开发人员

背景##

一般来说在业务代码中,加上 @Component, @Service@Repository, @Controller等注解就可以实现将bean注册到Spring中了。

但是在写框架,可能有些类会动态生成,怎么动态注册到Spring中呢?

BeanDefinitionRegistryPostProcessor 接口##

BeanDefinitionRegistryPostProcessor接口是一个可以修改spring工厂中已定义的bean的接口,该接口有个postProcessBeanDefinitionRegistry方法。

/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* [@param](https://my.oschina.net/u/2303379) registry the bean definition registry used by the application context
* [@throws](https://my.oschina.net/throws) org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

实现##

代码###

public class App implements BeanDefinitionRegistryPostProcessor{
@Override
public void postProcessBeanDefinitionRegistry(
BeanDefinitionRegistry registry) throws BeansException {
registry.registerBeanDefinition("demoEntityDao", getDefinition(AcAlert.class));
}
private BeanDefinition getDefinition(Class<?> cls) {
DaoInterfaceGenerator g = new DaoInterfaceGenerator(cls);
Class<?> daoClass = g.generateClass();
GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setBeanClass(MapperFactoryBean.class);
bd.getConstructorArgumentValues().addGenericArgumentValue(daoClass);
bd.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference("sqlSessionFactory")); return bd;
}
}

步骤说明###

  1. 实现BeanDefinitionRegistryPostProcessor接口
  2. 处理postProcessBeanDefinitionRegistry方法
  3. 生成BeanDefinition,上面展示了动态添加一个mybatis Dao的bean注册过程

我遇到的坑##

当动态生成生成mybatis的dao接口时,报这个错误:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'demoEntityDao': Post-processing of FactoryBean's singleton object failed; nested exception is java.lang.IllegalArgumentException: interface com.dhcc.ac.domain.AcAlertDao is not visible from class loader
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1590)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:254)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1054)
at com.dhcc.framework.App.main(App.java:48)
Caused by: java.lang.IllegalArgumentException: interface com.dhcc.ac.domain.AcAlertDao is not visible from class loader
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:581)
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:557)
at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230)
at java.lang.reflect.WeakCache.get(WeakCache.java:127)
at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:419)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:719)
at org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:121)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109)
at org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor.postProcessAfterInitialization(AbstractAdvisingBeanPostProcessor.java:90)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1723)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:113)
... 5 more

错误原因在于动态生成的class加载的classloader,与Proxy.newProxyInstance使用的ClassLoader,不是同一个classloader,所以在Proxy.newProxyInstance找不到这个新生成的类。

解决办法###

动态加载类,一般都是用defineClass动态加载到ClassLoader里去。

但defineClass不是public,所以在这里卡了一段时间。

后来,突然之间找到了解决办法,使用反射调用defineClass就好了呀。

小结##

技术没什么高深的,我后面将要写的一个功能,用到了本篇的技术,这里先介绍一下。


我的微信zouhaibin294148,不知不觉写了10多年代码了

如何动态在spring mvc中增加bean的更多相关文章

  1. Spring mvc 中使用 kaptcha 验证码

    生成验证码的方式有很多,个人认为较为灵活方便的是Kaptcha ,他是基于SimpleCaptcha的开源项目.使用Kaptcha 生成验证码十分简单并且参数可以进行自定义.只需添加jar包配置下就可 ...

  2. 7 -- Spring的基本用法 -- 5... Spring容器中的Bean;容器中Bean的作用域;配置依赖;

    7.5 Spring容器中的Bean 7.5.1 Bean的基本定义和Bean别名 <beans.../>元素是Spring配置文件的根元素,该元素可以指定如下属性: default-la ...

  3. Spring MVC 中的http Caching

    文章目录 过期时间 Last-Modified ETag Spring ETag filter Spring MVC 中的http Caching Cache 是HTTP协议中的一个非常重要的功能,使 ...

  4. spring mvc中使用freemark的一点心得

    参考文档: FreeMarker标签与使用 连接http://blog.csdn.net/nengyu/article/details/6829244 freemarker学习笔记--指令参考: ht ...

  5. Spring MVC中处理静态资源的多种方法

    处理静态资源,我想这可能是框架搭建完成之后Web开发的”头等大事“了. 因为一个网站的显示肯定会依赖各种资源:脚本.图片等,那么问题来了,如何在页面中请求这些静态资源呢? 还记得Spring MVC中 ...

  6. 解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException

    解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException这个问题出现的原因:一般在使用annotation的方式注入spring的bean 出现的,具体 ...

  7. Spring MVC 中的基于注解的 Controller【转】

    原文地址:http://my.oschina.net/abian/blog/128028 终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 H ...

  8. spring mvc中的文件上传

    使用commons-fileupload上传文件所需要的架包有:commons-fileupload 和common-io两个架包支持,可以到Apache官网下砸. 在配置文件spring-mvc.x ...

  9. spring mvc中的valid

    当你希望在spring mvc中直接校验表单参数时,你可以采用如下操作: 声明Validator的方式: 1.为每一个Controller声明一个Validator @Controller publi ...

随机推荐

  1. JDBC入门学习

    Introduction What's JDBC JDBC stands for Java Database Connectivity, which is a standard Java API fo ...

  2. sql注入的基本防范手段

    基本的sql注入防御手段,概括来讲就是权限控制和关键词过滤. 防御sql注入 ============================================================= ...

  3. DOM0,DOM2,DOM3 事件基础知识

    事件是javascript和HTML交互基础, 任何文档或者浏览器窗口发生的交互, 都要通过绑定事件进行交互; 事件有DOM0, DOM2和DOM3的区分(别问我怎么少了一个DOM1, 也没找到DOM ...

  4. nginx tomcat session丢失的问题

    nginx反向代理tomcat,出现seesion获取不到的问题. 网上搜索到的解决方案大多是集群tomcat共享session共享的问题,但我这个只有一台tomcat服务器,不涉及到服务器集群问题. ...

  5. 【转】PHP网站(nginx、php-fpm、mysql) 用户权限解析

    这篇文章我们就特别来讲解下,nginx.php-fpm 以及 mysql 运行在各个用户下的配置. 先来做个说明:nginx本身不能处理PHP,它只是个web服务器.当接收到客户端请求后,如果是php ...

  6. python爬虫小项目实战

  7. jQuery中10个非常有用的遍历函数

    使用jQuery,可以 很容易的选择HTML元素.但有些时候,在HTML结构较为复杂时,提炼我们选择的元素就是一件麻烦的事情.在这篇教程中,我们将探讨十种方 法去精炼和扩展我们将要操作的集合. HTM ...

  8. php时间类

    1.需求 数据库的时间都是用10个长度的时间戳存储,拿出来的时候要转为更易读的格式 2.例子 <?php class Mydate{ public function get_millisecon ...

  9. react+redux官方实例TODO从最简单的入门(4)-- 改

    上一篇文章实现了<删>这个功能,那么我们继续添加下一功能--<改> 这个修改的功能是通过双击每个子选项实现 第一步:按规矩来,添加一个状态声明 第二步:action中约定我们要 ...

  10. PHP获取某月天数

    方式一: <?php function days($year,$month){ if($month<10){ $month = '0'.$month; } if($month == 12) ...