Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基于类的包进行注入_Java_Spring_Spring Ioc - Fatal编程技术网

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
创建一个Java
Proxy
类,该类将在运行时根据调用程序包重定向到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支持的东西)。我问题中的例子其实是一个例子,没有什么正式的)。