框架:spring+struts2
spring负责对象管理,MVC;自动装配由struts2完成 (bean定义+getter/setter方法);
项目中用到了通过反射途径调用相应的业务模块的逻辑。controller接收http请求后,根据请求参数获得业务代码和方法参数,到.xml配置文件中读取相应的类名,方法名,参数类型列表,调用ReflectASM.jar(高效反射工具)中的
public static Object AsmMethodRefUtil.invokeAsmFunc(
String className, String methodName, Object[] paramValues, Class<?>[] paramTypes);
方法。该工具根据类名生成相应的对象,调用方法,传入参数列表并返回所调用的方法返回值。
我的问题是:需要在反射生成的对象中注入一个spring bean定义的对象,然而被注入的容器类本身不是spring bean组件,怎么办?
原理理解:
spring自动注入对象是通过创建一个BeanFactory并传入applicationContext配置文件对象,然后调用BeanFactory的getBean方法来实现相互依赖的对象获取和装配的。如果被注入的容器没有在spring bean中配置,而是通过反射途径生成,不能获取BeanFactory,就意味着不能进行自动注入。
如果在组件上实现一些spring提供的接口,如BeanFactoryAware、ApplicationContextAware,就可以手动方式获取BeanFactory,实现依赖注入。
在两个网页找到了共3种方法。
https://my.oschina.net/zhukp/blog/170855
http://www.cnblogs.com/Johness/archive/2012/12/25/2833010.html
我使用了第一个网页的第一种方法。
被注入的容器类需要extends BaseAutoAware。因为我的组件已经继承一个父类,我把其中的代码移植到了组件继承的父类中。
public class BaseWebService
{
public BaseSfqxWebService() {
((AutowireCapableBeanFactory)retrieveBeanFactory())
.autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
}
private BeanFactory retrieveBeanFactory() {
BaseLocator bl=new BaseLocator();
BeanFactory f = bl.getFactory();
return f;
}
}
BaseLocator类,实现BeanFactoryAware接口,获取BeanFactory对象:
(需要spring-beans-XXX.jar)
public class BaseLocator implements BeanFactoryAware {
private static BeanFactory factory = null;
private static BaseLocator baselocator = null;
@Override
public void setBeanFactory(BeanFactory f) throws BeansException {
factory = f;
}
public BeanFactory getFactory(){
return factory;
}
public static BaseLocator getInstance() {
if (baselocator == null)
baselocator = (BaseLocator) factory.getBean("baseLocator");
return baselocator;
}
}
在spring bean里做个配置
<bean id="baseLocator" class="com.landicorp.wsi.util.BaseLocator" />
其中getInstance()方法作者大约是漏掉了,所以一开始出现了组件父类中retrieveBeanFactory()方法返回BeanFactory为null的情况,搜索后终于找到原因,于是加上。
被注入的容器子类采用getter/setter方法注入。
public class MyLoginWebService extends BaseWebService
{
private IUserService userService;
public MyLoginWebService() {
super();
System.out.println(userService);
}
public IUserService getUserService() {
return userService;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
}
获取到的userService终于不为null了。
成功。
源码: 码云