zoukankan      html  css  js  c++  java
  • 如何动态在spring mvc中增加bean

    阅读对象##

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

    背景##

    一般来说在业务代码中,加上 @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多年代码了
    二维码

  • 相关阅读:
    nginx重启配置文件nginx.conf不成效
    nginx负载均衡简单配置
    linux下安装nginx
    一台服务器上部署多个tomcat
    tomcat三个端口作用
    tomcat三种部署方式
    查看端口占用, 杀掉
    java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    火狐浏览器发送post请求
    测试并发报错mysql: too many connections
  • 原文地址:https://www.cnblogs.com/binblog/p/6237031.html
Copyright © 2011-2022 走看看