先感叹一下:最近的项目真的很奇葩!!!

需求是这样的:我们的项目中引用了两个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



[置顶] spring巧用继承解决bean的id相同的问题的更多相关文章

  1. Spring框架是怎么解决Bean之间的循环依赖的 (转)

    问题: 循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环.比如A依赖于B,B依赖于C,C又依赖于A.如下图:   如何理解“依赖”呢,在Spring中有: 构造器循 ...

  2. [置顶] Spring中DI设置器注入

    Java的反射机制可以说是在Spring中发挥的淋漓尽致,下面要看的代码就是通过反射机制来实现向一个类注入其实际依赖的类型,这个过程的实现会交由Spring容器来帮我们完成. JavaBean中针对属 ...

  3. [置顶] Spring的DI依赖实现分析

    DI(依赖注入)是Spring最底层的核心容器要实现的功能之一,利用DI可以实现程序功能的控制反转(控制反转即程序之间之间的依赖关系不再由程序员来负责,而是由Spring容器来负责) 一个简单的例子( ...

  4. [置顶] spring集成mina 实现消息推送以及转发

    spring集成mina: 在学习mina这块时,在网上找了很多资料,只有一些demo,只能实现客户端向服务端发送消息.建立长连接之类.但是实际上在项目中,并不简单实现这些,还有业务逻辑之类的处理以及 ...

  5. [置顶] Spring的自动装配

    采用构造函数注入,以及setter方法注入都需要写大量的XML配置文件,这时可以采用另一种方式,就是自动装,由Spring来给我们自动装配我们的Bean. Spring提供了四种自动装配类型 1:By ...

  6. [置顶] Spring中自定义属性编辑器

    Spring中的属性编辑器能够自动的将String类型转化成需要的类型,例如一个类里面的一个整型属性,在配置文件中我们是通过String类型的数字进行配置的,这个过程中就需要一个转化操作,当然这个转化 ...

  7. [置顶] c++类的继承(inheritance)

    在C++中,所谓"继承"就是在一个已存在的类的基础上建立一个新的类.已存在的类(例如"马")称为"基类(base class )"或&quo ...

  8. xshell取消置顶

    现象:xshell置顶,导致无法正常浏览其他应用,文件等 原因分析:打开xshell时,触发其置顶快捷方式:Alt+A 解决建议:针对此问题,首先,可以从"查看栏"手动取消置顶:其 ...

  9. sql 中如何将返回的记录某一条置顶

    将table1中id 为2的记录置顶select * from table1order by case when id='2' then 0 else 1 end 例子:将已发布的置顶,status  ...

  10. jquery中的置顶,置底,向上,向下的排序功能

    css .selectedLi{background: #f0ad4e;color:#fff;} html部分 <ul class="seetSelect2" id='sys ...

随机推荐

  1. 面试官:你能简单聊聊MyBatis执行流程

    本文分享自华为云社区<面试必问|聊聊MyBatis执行流程?>,作者: 冰 河. MyBatis源码解析 大家应该都知道Mybatis源码也是对Jbdc的再一次封装,不管怎么进行包装,还是 ...

  2. NC224933 漂亮数

    题目链接 题目 题目描述 小红定义一个数满足以下条件为"漂亮数": 该数不是素数. 该数可以分解为2个素数的乘积. 4 是漂亮数,因为 4=2*2 21 是漂亮数,因为 21=3* ...

  3. Centos中安装deb报错

    centos7中安装deb包   概要:deb包和rpm包区别:deb后缀的软件包是for Debian系的(包括Ubuntu),不是给centos安装的:rpm后缀的软件包才是for Redhat系 ...

  4. Transform LiveData

    查询资料的其中一个场景: 创建一个回调函数,当查询后台的时候,后台有结果了,回调对应的回调函数,并将结果保存到LiveData中. public class DataModel {     ...   ...

  5. Spring Boot 加载外部配置文件

    Spring Boot 允许你从外部加载配置,这样的话,就可以在不同的环境中使用相同的代码.支持的外部配置源包括:Java属性文件.YAML文件.环境变量.命令行参数. 用@Value注解可以将属性值 ...

  6. 惠普HP519打印机缺色处理记录

    打印蓝色缺失, 黑色出墨不均匀 开盖检查, 发现蓝色墨水管路中间有断线, 拆开打印头后, 用随机器配的桔红色吸墨器吸墨. 之后重新开机还是缺色. 检查彩色打印头, 用浅浅的一层热水泡下方喷嘴, 黄色红 ...

  7. 【Android】使用ContentProvider实现跨进程通讯

    1 前言 ​ ContentProvider 即内容提供器,是 Android 四大组件之一,为 App 存取数据提供统一的对外接口,让不同的应用之间可以共享数据. ​ 如图,Server 端通过 C ...

  8. 初探富文本之文档diff算法

    初探富文本之文档diff算法 当我们实现在线文档的系统时,通常需要考虑到文档的版本控制与审核能力,并且这是这是整个文档管理流程中的重要环节,那么在这个环节中通常就需要文档的diff能力,这样我们就可以 ...

  9. WSL2镜像文件压缩

    WSL2的镜像文件(*.vhdx)支持自动扩容,但是一般不会自动缩容.一旦某次存放过大文件以后,即使后续删除,镜像文件体积仍然不会缩小,导致大量磁盘空间浪费.因此,可以定期对镜像文件进行手动压缩. 镜 ...

  10. OpenCV开发笔记(五十八):红胖子8分钟带你深入了解图像的矩(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...