spring巧用繼承解決bean的id相同的問題

NO IMAGE

先感嘆一下:最近的專案真的很奇葩!!!

需求是這樣的:我們的專案中引用了兩個jar包,這兩個jar包是其他專案組提供的,不能修改!

奇葩的是:這兩個jar中都需要引用方提供一個相同id的bean,而bean的定義卻是不同的,也就是雖然id相同,但他們對應的卻是兩個不同的java類,導致出現的問題是:該id對應的java類滿足了第一個jar包的要求,則不能滿足第二個jar包的要求,滿足了第二個jar包的要求,則不能滿足第一個jar包的要求,導致spring容器在啟動時就報錯。

 

那麼,該怎麼解決該問題呢?如何做才能符合兩個jar包的需求呢?經過仔細思考:發現通過java類的繼承可以巧妙的實現該需求,現示例如下:

spring主配置檔案:

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<import resource="classpath*:app1.xml"/>
<import resource="classpath*:app2.xml"/>
<import resource="classpath:appContext1.xml"/>
<!-- 	<import resource="classpath:appContext2.xml"/>  -->
</beans>

其中:app1.xml和app2.xml是兩個jar包app1.jar和app2.jar中對應的spring配置檔案


app1.jar和app2.jar中主要就有一個java編譯好後的class檔案和一個配置檔案:

其中app1.jar中的java檔案和配置檔案分別為:

Test1.java

package mypackage;
public class Test1 {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
@Override
public String toString() {
if(!this.getObj().getClass().getName().equals("mypackage.Obj1")){
try {
throw new Exception();
} catch (Exception e) {
System.err.println("test1--->mypackage.Test1依賴的obj型別錯誤,注入的不是mypacke.Obj1");
}
}
System.out.println("package.Test1");
return "package.Test1";
}
}

app1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="test1" class="mypackage.Test1">
<property name="obj">
<ref bean="mybean"/>
</property>
</bean>
</beans>

app2.jar中的java類和配置檔案分別為:

Test2.java

package mypackage;
public class Test2 {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
@Override
public String toString() {
if(!this.getObj().getClass().getName().equals("mypackage.Obj2")){
try {
throw new Exception();
} catch (Exception e) {
System.err.println("test2--->mypackage.Test2依賴的obj型別錯誤,注入的不是mypacke.Obj2");
}
}
System.out.println("package.Test2");
return "package.Test2";
}
}

app2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="test2" class="mypackage.Test2">
<property name="obj">
<ref bean="mybean"/>
</property>
</bean>
</beans>

其中:mybean是需要引用方提供的,這兩個jar中需要引用方提供的bean的id都是一樣的,這就導致了文章開始所提到的的問題。


測試程式:

package mypackage;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
/*	System.out.println(((Test1)context.getBean("child1")).getObj().getClass().getName());
System.out.println(((Test1)context.getBean("child2")).getObj().getClass().getName());*/
System.out.println(((Test1)context.getBean("test1")).getObj().getClass().getName());
System.out.println(((Test2)context.getBean("test2")).getObj().getClass().getName());
}
}

執行得到的兩個bean是相同的bean,不符合要求!!





解決方案:

引進兩個子類Child1和Child2,分別繼承jar包需要的Test1和Test2

Child1.java

package mypackage;
public class Child1 extends Test1 {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
@Override
public String toString() {
if(!this.getObj().getClass().getName().equals("mypackage.Hello")){
try {
throw new Exception();
} catch (Exception e) {
System.err.println("child1--->mypackage.Test依賴的obj注入的型別錯誤,注入的不是mypacke.Hello");
}
}
return "package.Test1";
}
}

Child2.java

package mypackage;
public class Child2 extends Test2 {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
@Override
public String toString() {
if(!this.getObj().getClass().getName().equals("mypackage.World")){
try {
throw new Exception();
} catch (Exception e) {
System.err.println("child2--->mypackage.Test2依賴的obj注入的型別錯誤,注入的不是mypacke.World");
}
}
return "package.Test2";
}
}

新增一個新的spring輔助配置檔案:

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="obj1" class="mypackage.Obj1"></bean>
<bean id="obj2" class="mypackage.Obj2"></bean>
<bean id="mybean1" class="mypackage.Obj2"></bean>
<bean id="mybean2" class="mypackage.Obj2"></bean>
<bean id="child1" class="mypackage.Child1">
<property name="obj">
<ref bean="mybean1"/>
</property>
</bean>
<bean id="child2" class="mypackage.Child2">
<property name="obj">
<ref bean="mybean2"/>
</property>
</bean>
</beans>

在spring主配置檔案做修改如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- <import resource="classpath*:app1.xml"/>
<import resource="classpath*:app2.xml"/> -->
<import resource="classpath:appContext1.xml"/>
<import resource="classpath:appContext2.xml"/> 
</beans>

測試程式:

package mypackage;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//System.out.println(context);
/*System.out.println(((Test2)(context.getBean("test2"))).getObj().getClass().getName());
System.out.println(((Test)(context.getBean("test"))).getObj().getClass().getName());*/
//System.out.println(context.getBean("mybean").getClass().getName());
System.out.println(context.getBean("child1"));
System.out.println(context.getBean("child2"));
/*		System.out.println(context.getBean("mypackage.Hello"));
System.out.println(context.getBean("mypackage.Hello#1"));*/
}
}

執行得到:獲取的是不同的bean,也就是間接實現了兩個jar包中需要提供同名id的bean,但bean對應的java類是不同的java類的需求!


總結:實際上就是物件導向的lisp原則,就是里氏替換原則,具體點就是凡是父類出現的地方,都可以用子類來代替!

例子很簡單,但是能說明問題。


github上原始碼地址:https://github.com/iamzken/kuaiqian/tree/master/spring-same-id-bean-test