Java 基于类的包进行注入
我有两个包含类的模块:Java 基于类的包进行注入,java,spring,spring-ioc,Java,Spring,Spring Ioc,我有两个包含类的模块: blog.model.ArticleDAO blog.model.CategoryDAO users.model.UserDAO users.model.UserGroupDAO 所有这些DAO都依赖于相同的服务,但我需要基于包注入不同的实例 我的意思是模块博客应该有一个特定的MyService实例,模块用户应该有另一个MyService实例 我不想创建两个命名的服务,因为有一天我可能希望对所有DAO使用相同的服务。或者我也可以为一个特定的类注入另一个特定的实例 是否
blog.model.ArticleDAO
blog.model.CategoryDAO
users.model.UserDAO
users.model.UserGroupDAO
所有这些DAO都依赖于相同的服务,但我需要基于包注入不同的实例
我的意思是模块博客应该有一个特定的MyService
实例,模块用户应该有另一个MyService
实例
我不想创建两个命名的服务,因为有一天我可能希望对所有DAO使用相同的服务。或者我也可以为一个特定的类注入另一个特定的实例
是否有方法基于类的包注入服务?
可以这样说:
- 将
(foo
的实例)注入到MyService
blog.*
- 将
(bar
的实例)注入到MyService
用户中的类中。*
但是让我所有的班级都不知道这一点!他们的配置应该只声明“注入
MyService的实例”首先我想说,我发现这是一个奇怪的要求。我还想知道为什么您的DAO需要服务。在普通的分层设计中,情况正好相反(服务使用DAO)
然而,我发现这个挑战很有趣,我尝试使用FactoryBean
创建一个JavaProxy
类,该类将在运行时根据调用程序包重定向到MyService的正确实例。代码如下:
public class CallerPackageAwareProxyFactoryBean implements
FactoryBean<MyService>, ApplicationContextAware {
private Class<?> targetServiceType;
private ApplicationContext applicationContext;
private InvocationHandler invocationHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (ReflectionUtils.isEqualsMethod(method)) {
// Only consider equal when proxies are identical.
return (proxy == args[0]);
} else if (ReflectionUtils.isHashCodeMethod(method)) {
// Use hashCode of service locator proxy.
return System.identityHashCode(proxy);
} else if (ReflectionUtils.isToStringMethod(method)) {
return "Service dispatcher: " + targetServiceType.getName();
} else {
String callerPackageFirstLevel = getCallerPackageFirstLevel();
Map<String, ?> beans = applicationContext
.getBeansOfType(targetServiceType);
for (Map.Entry<String, ?> beanEntry : beans.entrySet()) {
if (beanEntry.getKey().startsWith(callerPackageFirstLevel)) {
return method.invoke(beanEntry.getValue(), args);
}
}
throw new IllegalArgumentException(
String.format(
"Could not find any valid bean to forward call for method %s.",
method.getName()));
}
}
private String getCallerPackageFirstLevel() {
Throwable t = new Throwable();
StackTraceElement[] elements = t.getStackTrace();
String callerClassName = elements[3].getClassName();
return callerClassName.split("\\.")[0];
}
};
public MyService getObject() throws Exception {
return (MyService) Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), new Class<?>[] { MyService.class },
invocationHandler);
}
public Class<?> getObjectType() {
return MyService.class;
}
public boolean isSingleton() {
return true;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void setTargetServiceType(Class<?> targetServiceType) {
this.targetServiceType = targetServiceType;
}
}
公共类CallerPackageAwareProxyFactoryBean实现
FactoryBean,ApplicationContextAware{
私有类targetServiceType;
私有应用程序上下文应用程序上下文;
private InvocationHandler InvocationHandler=new InvocationHandler(){
公共对象调用(对象代理、方法、对象[]参数)
扔掉的{
if(反射率直到isEqualsMethod(方法)){
/当代理相同时,只考虑相等。
返回(proxy==args[0]);
}else if(ReflectionUtils.isHashCodeMethod(方法)){
//使用服务定位器代理的哈希代码。
返回系统。身份验证码(代理);
}else if(ReflectionUtils.isToStringMethod(方法)){
返回“服务调度器:”+targetServiceType.getName();
}否则{
字符串callerPackageFirstLevel=getCallerPackageFirstLevel();
MapBeans=applicationContext
.getBeansOfType(targetServiceType);
for(Map.Entry-beans:beans.entrySet()){
if(beanEntry.getKey().startsWith(callerPackageFirstLevel)){
返回方法.invoke(beanEntry.getValue(),args);
}
}
抛出新的IllegalArgumentException(
字符串格式(
“找不到任何有效的bean来转发方法%s的调用。”,
方法(getName());
}
}
私有字符串getCallerPackageFirstLevel(){
可丢弃t=新的可丢弃();
StackTraceElement[]元素=t.getStackTrace();
字符串callerClassName=元素[3]。getClassName();
返回callerClassName.split(“\\”)[0];
}
};
public MyService getObject()引发异常{
return(MyService)Proxy.newProxyInstance(Thread.currentThread())
.getContextClassLoader(),新类[]{MyService.Class},
调用处理程序);
}
公共类getObjectType(){
返回MyService.class;
}
公共布尔isSingleton(){
返回true;
}
public void setApplicationContext(ApplicationContext ApplicationContext){
this.applicationContext=applicationContext;
}
public void setTargetServiceType(类targetServiceType){
this.targetServiceType=targetServiceType;
}
}
我不需要对Dao或服务配置进行任何更改。我只需要在Spring上下文中添加FactoryBean的创建:
<bean id="myService" class="stackoverflow.CallerPackageAwareProxyFactoryBean">
<property name="targetServiceType" value="a.b.c.MyService" />
</bean>
也许有几点意见:
- 只能通过创建异常并查看stacktrace来获取调用程序包
InvocationHandler
的代码源于
- 我仍然想知道是否有更简单的方法,但我认为没有
- 您可以替换调用处理程序的一部分以使用配置映射(package=>myservicebeanname)
- 我不建议在生产环境中使用此类代码李>
哇,好的,谢谢你的回答!我期待一个配置选项(Spring支持的东西)。我问题中的例子其实是一个例子,没有什么正式的)。