java相关:Spring动态加载bean后调用实现方法解析

发布于 2020-8-4|

复制链接

摘记: 前言在使用Spring的过程中,我们有时候并不想通过xml的方式进行bean的注入,希望在不改变原有的程序结构的基础上添加我们需要的bean,这个时候我们可以利用Spring的spring-beans的jar包里提供的BeanFactoryPostProcessor接口类,通过实现这个接口类,我们可以动态 ..

前言在使用Spring的过程中,我们有时候并不想通过xml的方式进行bean的注入,希望在不改变原有的程序结构的基础上添加我们需要的bean,这个时候我们可以利用Spring的spring-beans的jar包里提供的BeanFactoryPostProcessor接口类,通过实现这个接口类,我们可以动态的加载所需要的bean,特别是在引入已经打包在jar里面的程序而没有办法做出修改的情况下,这个接口就为我们提供了及其方便的入口。因为我是在其他项目的基础上测试的这个接口,所以引入的jar有其特殊性,所以需要参考的同学可以按照自己的需求来实现。1.通过pom.xml来引入springboot:

```xml
org.springframework.boot
spring-boot-starter-parent
1.5.6.RELEASE
org.springframework.boot
spring-boot-starter-test
org.springframework.boot
spring-boot-starter-web
com.thread
test
1.0
system
f:/threadTest.jar
```
2.创建App.java启动类:
```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author liaoyubo
* @version 1.0 2017/7/31
* @description
*/
@SpringBootApplication
public class App {
public static void main(String [] args){
SpringApplication.run(App.class);
}
}
```
3.创建一个DynamicCreateBean.java来作为动态加载的对象:
```java
public class DynamicCreateBean {
public void printMethod(){
System.out.println("DynamicCreateBean Success");
}
}

```

4.在本项目外另外新增一个项目打成jar的形式导入到该项目中用于测试动态加载,在我的项目中新增的是threadTest.jar,该包是一个用于多线程测试的类,需要的同学自己随便新建一个来打成jar包测试即可。5.新增一个LoadBean.java类用于动态加载bean:

```java
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.stereotype.Component;
import com.thread.mulitSynThreadTest.Run;
/**
* @author liaoyubo
* @version 1.0 2017/8/11
* @description
*/
@Component
public class LoadBean implements BeanFactoryPostProcessor {
private DefaultListableBeanFactory defaultListableBeanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
this.defaultListableBeanFactory = (DefaultListableBeanFactory)configurableListableBeanFactory;
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition("com.springRedis.dynamic.DynamicCreateBean");
//用于设置指定的类中需要引入的其他bean
//beanDefinitionBuilder.addPropertyValue("otherBeanName","otherBeanName");
this.defaultListableBeanFactory.registerBeanDefinition("dynamicCreateBean",beanDefinitionBuilder.getBeanDefinition());
beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Run.class.getName());
//用于设置指定的类中需要引入的其他bean
//beanDefinitionBuilder.addPropertyValue("otherBeanName","otherBeanName");
this.defaultListableBeanFactory.registerBeanDefinition("mulitRun",beanDefinitionBuilder.getBeanDefinition());
}
}
```

6.创建测试类:

```java
import com.springRedis.App;
import com.springRedis.dynamic.DynamicCreateBean;
import com.thread.mulitSynThreadTest.Run;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author liaoyubo
* @version 1.0 2017/8/11
* @description
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class MultiTest {
@Autowired
private DynamicCreateBean dynamicCreateBean;
@Autowired
private Run run;
@Test
public void testDynamic(){
dynamicCreateBean.printMethod();
run.printRun();
}
}
```

以上就是整个的动态加载过程,如果需要了解更多,可以在网上继续查找资料。最近在看spring cloud Feign相关文章时发现了另外一种注入动态bean的方式,里面的代码提供是在FeignClientsRegistrar.java类中具体代码为:

```java
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) {
String className = annotationMetadata.getClassName();
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
this.validate(attributes);
definition.addPropertyValue("url", this.getUrl(attributes));
definition.addPropertyValue("path", this.getPath(attributes));
String name = this.getName(attributes);
definition.addPropertyValue("name", name);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(2);
String alias = name + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
boolean primary = ((Boolean)attributes.get("primary")).booleanValue();
beanDefinition.setPrimary(primary);
String qualifier = this.getQualifier(attributes);
if(StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
```