目录
1. 背景
单例对象引用原型对象时,每次创建的单例对象中,原型对象都是同一个对象,不能满足每次返回不同原型对象的目的
/**
* 原型对象
*/
public class MyPrototype {}
/**
* 单例对象
*/
public class MySingleton {
// 单例对象引用原型对象
private MyPrototype myPrototype;
public MyPrototype getMyPrototype() {
return myPrototype;
}
public void setMyPrototype(MyPrototype myPrototype) {
this.myPrototype = myPrototype;
}
}
self06_overrideMethod.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="mySingleton" class="self06_overrideMethod.singletonReferPrototype.MySingleton" scope="singleton">
<property name="myPrototype" ref="myPrototype"/>
</bean>
<bean id="myPrototype" class="self06_overrideMethod.singletonReferPrototype.MyPrototype" scope="prototype"/>
</beans>
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("self06_overrideMethod.xml");
MySingleton mySingleton = context.getBean(MySingleton.class);
System.out.println(mySingleton.getMyPrototype());
System.out.println(mySingleton.getMyPrototype());
System.out.println(mySingleton.getMyPrototype());
}
}
---------console----三次打印的时同一个对象---------------
self06_overrideMethod.singletonReferPrototype.MyPrototype@8646db9
self06_overrideMethod.singletonReferPrototype.MyPrototype@8646db9
self06_overrideMethod.singletonReferPrototype.MyPrototype@8646db9
2. <lookup-method> 解决单例引用原型问题
public class Fruit {
public Fruit() {
System.out.println("I got Fruit");
}
}
/** 原型prototype */
public class Apple extends Fruit {
public Apple() {
System.out.println("I got a fresh apple");
}
}
/** 单例singleton */
public abstract class FruitPlant {
/**
* 此方法调用时会被FruitPlant的CGLIB代理对象的
* CglibSubclassingInstantiationStrategy-LookupOverrideMethodInterceptor拦截器的intercept()方法拦截
* 其中的createBean()流程,会根据配置中<lookup-method name="getFruit" bean="apple"/>
* bean="apple"这个bean是singleton还是prototype选择从缓存中取还是重新创建新的bean返回
*/
public abstract Fruit getFruit();
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="apple" class="self06_overrideMethod.lookupmethod.Apple" scope="prototype"/>
<!--单例fruitPlant1通过lookup-method标签实现每次调用getFruit方法都返回不一样的原型Apple对象-->
<bean name="fruitPlant1" class="self06_overrideMethod.lookupmethod.FruitPlant" scope="singleton">
<lookup-method name="getFruit" bean="apple"/>
</bean>
</beans>
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("self06_overrideMethod.xml");
//创建单例CGLIB代理的FruitPlant对象
FruitPlant fruitPlant1 = (FruitPlant) context.getBean("fruitPlant1");
//getFruit()会被fruitPlant1的LookupOverrideMethodInterceptor拦截器拦截-》
//通过调用getBean(),根据<lookup-method>中定义返回的bean是单例还是原型来返回缓存对象或重新创建对象
Fruit fruit1 = fruitPlant1.getFruit();
System.out.println(fruit1);
Fruit fruit11 = fruitPlant1.getFruit();
System.out.println(fruit11);
}
}
----------concole-------可以看到调用了两次Apple构造方法创建了2个不同的Apple对象返回--------------
I got Fruit
I got a fresh apple
self06_overrideMethod.lookupmethod.Apple@5bb21b69
I got Fruit
I got a fresh apple
self06_overrideMethod.lookupmethod.Apple@6b9651f3
3. <replace-method> 实现动态替换方法体
目的:当OriginalDog对象调用sayHello()方法时,走ReplaceDog的implement方法逻辑
public class OriginalDog {
public void sayHello() {
System.out.println("Hello,I am a original dog...");
}
public void sayHello(String name) {
System.out.println("Hello,I am a original dog, my name is " + name);
}
}
// 替换类需实现MethodReplacer接口,并重写reimplement方法,此方法内容即新的方法逻辑
public class ReplaceDog implements MethodReplacer {
/**
* @param obj OriginalDog的CGLIB代理对象
* @param method 被代理的sayHello()或sayHello(String name)方法
* @param args 被代理方法的参数
* @return OriginalDog的CGLIB代理对象
*/
@Override
public Object reimplement(Object obj, Method method, Object[] args) {
System.out.println("Hello, I am a replace dog...");
Arrays.stream(args).forEach(str -> System.out.println("参数:" + str));
return obj;
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("self06_overrideMethod.xml");
// 这里会生成originalDog的CGLIB代理对象
OriginalDog originalDog = context.getBean(OriginalDog.class);
/**
* 会被CglibSubclassingInstantiationStrategy-ReplaceOverrideMethodInterceptor.intercept()方法拦截
* 会先获取<replaced-method name="sayHello" replacer="replaceDog" />中replacer对应的bean
* 然后调用replacer重写的reimplement方法,完成方法逻辑动态替换
*/
originalDog.sayHello();
System.out.println("-----------------------");
originalDog.sayHello("ssss");
}
}
--------console--------------
Hello, I am a replace dog...
-----------------------
Hello, I am a replace dog...
参数:ssss
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- ====================replace-method属性注入==================== -->
<bean id="replaceDog" class="self06_overrideMethod.replacemethod.ReplaceDog"/>
<bean id="originalDog" class="self06_overrideMethod.replacemethod.OriginalDog">
<!--将OriginalDog的sayHello()方法替换为ReplaceDog的reimplement方法-->
<replaced-method name="sayHello" replacer="replaceDog" />
<!--将OriginalDog的sayHello(String name)方法替换为ReplaceDog的reimplement方法-->
<replaced-method name="sayHello" replacer="replaceDog">
<arg-type match="java.lang.String" />
</replaced-method>
</bean>
</beans>
本文详细介绍了在Spring框架下如何解决单例对象引用原型对象导致的问题,以及如何利用<lookup-method>和<replace-method>标签实现动态替换方法体。通过实例展示了这两种技术的使用方法,使得每次调用都能返回不同的原型对象,并且能够动态改变对象的方法逻辑。
1万+

被折叠的 条评论
为什么被折叠?



