您的位置:首页 > 编程语言 > Java开发

用spring做领域对象的依赖注入

2017-06-12 00:00 232 查看
依赖注入是现在一个使用非常广泛的技术,极大的降低了编写程序的难度。对于领域层的代码,我们也想使用依赖注入。对于无状态的service repository factory等对象,我们可以用spring容器初始化它们,把它们作为普通的spring的bean,这样它们天生就能被注入依赖了。对于entity, value objects这些有状态的对象,依赖注入就有点麻烦了。

让spring帮我们注入依赖

如果手动注入依赖,会很麻烦,如下:

public class CFactory {
private A a;
private B b;

public C creaetC() {
C c = new C(); //手动注入依赖
c.setA(a);
c.setB(b);
return c;
}

@Autowired
public void setA(A a) {
this.a = a;
}

@Autowired
public void setB(B a) {
this.b = b;
}
}

这样不仅代码量大,而且不灵活,如果以后C需要注入其它依赖,所有初始它的地方都要多写很多代码。因此,我们需要spring能够帮助我们自动注入依赖。通过下面的代码可以完成:

public class AutowireInjector implements ApplicationContextAware {
private ApplicationContext applicationContext;

public void autowire(Object bean) {
this.applicationContext.getAutowireCapableBeanFactory().autowireBean(bean);
}

public void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) {
this.applicationContext.getAutowireCapableBeanFactory().autowireBeanProperties(existingBean, autowireMode, dependencyCheck);
}

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

通过调用autowire方法,会自动根据对象里的@Autowired注入依赖,如下:

public class C {
private A a;
private B b;

@Autowired
public void setA(A a) {
this.a = a;
}

@Autowired
public void setB(B a) {
this.b = b;
}
}

public class CFactory {
private AutowireInjector autowireInjector;

public C creaetC() {
C c = new C();
//spring 会自动注入依赖 a b
this.autowireInjector.autowire(c);
return c;
}

@Autowired
public void setAutowireInjector(AutowireInjector autowireInjector) {
this.autowireInjector = autowireInjector;
}
}

这样不论C的依赖要求如何变化,CFactory里面都只要注入autowireInjector就行了。改了C不需要动CFactory。

利用AOP简化依赖注入

尽管有了AutowireInjector,但是还要注入很多AutowireInjector,手动调用autowire方法,还是不够方便。假如限定Entity只能通过Factory或Repository获取,我们就可以使用AOP,对Factory和Repository返回的领域对象注入依赖。用如下代码实现:

@Component
@Aspect
public class AutoWireAopConfig {
private AutowireInjector autowireInjector;

@Pointcut("execution(public * com.my..*Factory.create*(..))")
public void factoryCreate() {
}

;

@Pointcut("execution(public * com.my..*Repository.find*(..))")
public void repositoryFind() {
}

;

@AfterReturning(pointcut = "factoryCreate() || repositoryFind()", returning = "returnObject")
public void injectAutowire(Object returnObject) {
doInjection(returnObject);
}

public void doInjection(Object o) {
if (o == null) {
return;
}
if (o instance
7fe8
of Collection) {
Collection c = (Collection) o;
for (Object subObject : c) {
doInjection(subObject);
}
return;
}
if (o.getClass().isArray()) {
int length = Array.getLength(o);
for (int i = 0; i < length; i++) {
doInjection(Array.get(o, i));
}
return;
}
if (o instanceof Map) {
Collection c = ((Map) o).values();
for (Object subObject : c) {
doInjection(subObject);
}
return;
}
if (o.getClass().getCanonicalName().startsWith("com.my")) {
this.autowireInjector.autowire(o);
}
}

@Autowired
public void setAutowireInjector(AutowireInjector autowireInjector) {
this.autowireInjector = autowireInjector;
}
}

这样,只要Factory和Repository以Factory和Repository作为类名的后缀,以create find作为方法的前缀,其返回值就会被注入依赖,而且支持返回领域对象集合。那此不通过Factory和Repository创建的对象,还是须要手动的注入依赖。

给hibernate载入的对象注入依赖

如果对象是通过hibernate从数据库载入的,那么可以通过hibernate的EntityListener注入依赖。首先得定义Listener类:

public class HibernateEntityDependencyInjector implements PostLoadEventListener, MergeEventListener {
private AutowireInjector autowireInjector;

@Override
public void onPostLoad(PostLoadEvent event) {
this.injectDependency(event.getEntity());
}

@Override
public void onMerge(MergeEvent event) throws HibernateException {
this.injectDependency(event.getEntity());
}

@Override
public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException {
this.injectDependency(event.getEntity());
}

protected void injectDependency(Object obj) {
if (obj != null) {
this.autowireInjector.autowire(obj);
}
}

@Autowired
public void setAutowireInjector(AutowireInjector autowireInjector) {
this.autowireInjector = autowireInjector;
}
}

然后通过spring,把它配置到SessionFactory里面:

<bean id="hibernateEntityDependencyInjector" class="com.my.HibernateEntityDependencyInjector"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:/hibernate.cfg.xml"/>
<property name="eventListeners">
<map>
<entry key="post-load" value-ref="hibernateEntityDependencyInjector"/>
<entry key="merge" value-ref="hibernateEntityDependencyInjector"/>
</map>
</property>
</bean>

这样,在post-load和merge的时候,会注入依赖。对于@Embedded的对象,这样是不管用的,还没有找到更好的办法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ddd hibernate ioc spring