Table of contents
static proxy
Both the proxied class and the proxy class implement the Apple interface
public interface Apple {
Integer buyApple();
}
Create an instance of "Yantai" apple as the proxy class, which mainly implements a method of buying apples, which is also the method mainly used to be enhanced by the proxy later.
public class YanTaiApple implements Apple{
private Integer price;
public YanTaiApple(Integer price) {
this.price = price;
}
@Override
public Integer buyApple(){
return this.price;
}
}
Create a proxy class for "Yantai" Apple, which mainly acts as a middleman, and the main enhancement is that the price is higher.
public class YanTaiAppleProxy implements Apple{
private Apple apple;
public YanTaiAppleProxy(Apple apple) {
this.apple = apple;
}
@Override
public Integer buyApple() {
Integer price = apple.buyApple()+2;
System.out.println("苹果收购价格"+apple.buyApple()+"元,出售价"+price+"元");
return price;
}
}
In the following method, we go to buy apples through agents...
public class StaticProxyTest {
@Test
public void test(){
Apple apple = new YanTaiAppleProxy(new YanTaiApple(3));
apple.buyApple();
}
}
======结果======
苹果收购价格3元,出售价5元
Dynamic proxy
Carefully analyze the above static proxy, we will find that different proxy classes must be created for each class. If there are Henan apples, Xinjiang apples, Zhaotong apples.... Create a proxy class, can't we use one proxy to proxy multiple apples? Obviously static proxy is very limited.
Dynamic proxy is a proxy class that can dynamically create the original class through reflection, and then replace the original class with the proxy class in the system. In the java language, dynamic proxy is mainly implemented through the reflection mechanism.
JDK dynamic proxy
The jdk dynamic proxy is mainly implemented based on the interface and the Proxy class in the java reflection package, that is, the proxy class and the proxy class implement the same interface, and then dynamically expand through the Proxy proxy interface (emm.... Mainly see the following implementation ).
We continue to use the above Apple and YanTaiApple for both the interface and the original class, and then the proxy class is implemented as follows, we need to implement the interface InvocationHandler and then enhance the method call in the invoke method (the price of the agent increases by two yuan), when the original class associates this After the proxy class, the method of executing the interface will automatically enter the invoke method for enhancement.
public class AppleProxyHandler implements InvocationHandler {
private Apple apple;
public AppleProxyHandler(Apple apple) {
this.apple = apple;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取price字段
Field field = apple.getClass().getDeclaredField("price");
//放开权限 - 针对private
field.setAccessible(true);
Integer price = (Integer) field.get(apple);
//重新设置值
field.set(apple,price+2);
return method.invoke(apple,args);
}
}
Associate YanTaiApple and AppleProxyHandler instances through Proxy. Of course, the construction parameters of AppleProxyHandler can not only pass in the YanTaiApple instance, but also pass in the instance of other classes that implement the Apple interface, that is to say, AppleProxyHandler can proxy all the implementation classes of the Apple interface.
public class JdkProxyTest {
@Test
public void test(){
//关联
Apple apple = (Apple) Proxy.newProxyInstance(this.getClass().getClassLoader(),
new Class[]{Apple.class},
new AppleProxyHandler(new YanTaiApple(2)));
System.out.println(apple.buyApple());
}
}
=====结果=====
4
It is slightly unreasonable to carefully consider the above design, because the Apple interface may not only have the buyApple method but also other methods, so our proxy class clearly wants to be represented by the buyApple method, so the following optimization can be done.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("buyApple".equals(method.getName())) {
//获取price字段
Field field = apple.getClass().getDeclaredField("price");
//放开权限 - 针对private
field.setAccessible(true);
Integer price = (Integer) field.get(apple);
//重新设置值
field.set(apple, price + 2);
}
return method.invoke(apple,args);
}
cglib dynamic proxy
The main difference between cglib proxy and jdk proxy is that jdk dynamic proxy only supports interface proxy but not class proxy. The second parameter of Proxy.newProxyInstance
can only be passed in the set of class objects of the interface. If a class is passed in, it will report java.lang.IllegalArgumentException: java.lang.Object is not an interface
Exception. And cglib implements dynamic proxy through inheritance, and will dynamically generate a subclass object of the proxy class at runtime, so if this class is final modified, it cannot be proxy by cglib.
Let's continue to use Apple's example, but using cglib dynamic proxy, we don't need a unified interface class.
public class YanTaiApple {
public Integer price;
public YanTaiApple(Integer price) {
this.price = price;
}
public Integer buyApple(){
return this.price;
}
}
The proxy class implements the MethodInterceptor interface and then implements the proxy logic in the intercept method
public class AppleProxy implements MethodInterceptor {
@Override
public Object intercept(Object apple, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//apple是动态生成YanTaiApple的一个子类
Field field = apple.getClass().getSuperclass().getDeclaredField("price");
field.setAccessible(true);
Integer price = (Integer) field.get(apple);
field.set(apple,price+2);
return methodProxy.invokeSuper(apple,objects);
}
}
The test class needs to use the Enhancer class to set the proxy class to SuperClass and the proxy class to Callback
public class CglibProxyTest {
@Test
public void test(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(YanTaiApple.class);
enhancer.setCallback(new AppleProxy());
//参数类型、参数值 - create相当于构造函数
YanTaiApple yanTaiApple = (YanTaiApple) enhancer.create(new Class[]{Integer.class}, new Integer[]{3});
System.out.println(yanTaiApple.buyApple());
}
}
=====结果=====
5
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。