搭框架人员,或者其余感兴趣的开发人员java
通常来讲在业务代码中,加上 @Component
, @Service
,@Repository
, @Controller
等注解就能够实现将bean注册到Spring中了。
可是在写框架,可能有些类会动态生成,怎么动态注册到Spring中呢?spring
BeanDefinitionRegistryPostProcessor
接口BeanDefinitionRegistryPostProcessor接口是一个能够修改spring工厂中已定义的bean的接口,该接口有个postProcessBeanDefinitionRegistry方法。sql
/** * 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; } }
BeanDefinitionRegistryPostProcessor
接口postProcessBeanDefinitionRegistry
方法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
找不到这个新生成的类。mybatis
动态加载类,通常都是用defineClass动态加载到ClassLoader里去。
但defineClass不是public,因此在这里卡了一段时间。
后来,忽然之间找到了解决办法,使用反射调用defineClass就行了呀。app
技术没什么高深的,我后面将要写的一个功能,用到了本篇的技术,这里先介绍一下。框架
个人微信zouhaibin294148,不知不觉写了10多年代码了
dom