代理模式
讲代理模式之前,我们要先明白什么是“代理”
代理:简单来说就是将事情交给代替你去处理
代理分为 静态代理 和 动态代理
静态代理
直接为每一个实现类写一个代替类
接口:
public interface IMath {
int add(int n1, int n2);
int sub(int n1, int n2);
int mut(int n1, int n2);
}
实现类:
package com.nf147.ssm.springAOP.service;
public class Math implements IMath {
@Override
public int add(int n1, int n2) {
int result = n1 + n2;
System.out.println(n1 + "+" + n2 + "=" + result);
return result;
}
@Override
public int sub(int n1, int n2) {
int result = n1 - n2;
System.out.println(n1 + "-" + n2 + "=" + result);
return result;
}
@Override
public int mut(int n1, int n2) {
int result = n1 / n2;
System.out.println(n1 + "/" + n2 + "=" + result);
return result;
}
}
代理类:
package com.nf147.ssm.springAOP.proxy;
import com.nf147.ssm.springAOP.service.IMath;
import com.nf147.ssm.springAOP.service.Math;
import java.util.Random;
// IMath的静态代理类
public class MathProxy implements IMath {
IMath iMath = new Math();
@Override
public int add(int n1, int n2) {
long start = System.currentTimeMillis();
lazy();
int result = iMath.add(n1, n2);
Long span = System.currentTimeMillis() - start;
System.out.println("共用时:" + span);
return result;
}
@Override
public int sub(int n1, int n2) {
long start = System.currentTimeMillis();
lazy();
int result = iMath.sub(n1, n2);
Long span = System.currentTimeMillis() - start;
System.out.println("共用时:" + span);
return result;
}
@Override
public int mut(int n1, int n2) {
long start = System.currentTimeMillis();
lazy();
int result = iMath.mut(n1, n2);
Long span = System.currentTimeMillis() - start;
System.out.println("共用时:" + span);
return result;
}
// 人为延时
public void lazy(){
try {
int n = (int)new Random().nextInt(500);
Thread.sleep(n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试:
// 静态代理
IMath math = new MathProxy();
@org.junit.Test
public void test01() {
int n1 = 100, n2 = 5;
math.add(n1, n2);
math.sub(n1, n2);
math.mut(n1, n2);
}
结果:
这种模式的优点:客户端不需要知道实现类是什么,怎么做的,只需要知道代理就可以了
缺点:代理类和委托类继承了相同的接口,代理类通过委托类实现了相同的方法,使得出现了大量重复的代码,
如果接口增加一个方法,那么不仅仅是实现类要去实现这个方法,所有的代理类也要去实现这个方法,这就增加了代码的复杂度;
动态代理
动态代理又分为:JDK代理对象 和 CGLib代理对象
JDBK代理对象:是java.lang.reflect.*包提供的方式,它必须借助于一个接口才能产生代理对象
代理类:
package com.nf147.ssm.springAOP.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Random; // 动态代理类 public class DynamicProxy implements InvocationHandler { Object object; public Object getProxyObject(Object object){ this.object = object; return Proxy.newProxyInstance( object.getClass().getClassLoader(), object.getClass().getInterfaces(), this ); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.currentTimeMillis(); lazy(); Object result = method.invoke(object,args); Long span = System.currentTimeMillis() - start; System.out.println("共用时:" + span); return result; } // 模拟延时 public void lazy(){ try { int n = (int)new Random().nextInt(500); Thread.sleep(n); } catch (InterruptedException e) { e.printStackTrace(); } } }
测试:
// 动态代理
IMath math2 = (IMath) new DynamicProxy().getProxyObject(new Math());
@org.junit.Test
public void test02() {
int n1 = 100, n2 = 5;
math2.add(n1, n2);
math2.sub(n1, n2);
math2.mut(n1, n2);
}
结果:
因为 JDK 动态代理必须要提供接口才能使用,在一些不能提供接口的环境中,它就不适用了
CGLIb动态代理
它是一个开源项目,是一个强大的,高性能的,高质量的Code生成类库,它可以在运行期扩展 Java 类和实现 Java 接口,
通俗说 cglib 可以在运行时动态生成字节码。
在使用前,要先去 https://mvnrepository.com/artifact/cglib/cglib/3.2.4 添加 cglib 包
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
代理类:
package com.nf147.ssm.springAOP.proxy;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
import java.util.Random;
// CGLib
// 动态代理类
public class CGLibProxy implements MethodInterceptor {
// 被代理的对象
Object object;
public Object getObject(Object object) {
this.object = object;
// 增强器,动态代码生成器
Enhancer enhancer = new Enhancer();
// 回调方法
enhancer.setCallback((Callback) this);
// 设置生成类的父类类型
enhancer.setSuperclass(object.getClass());
// 动态生成字节码并返回代理对象
return enhancer.create();
}
// 拦截方法
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
long start = System.currentTimeMillis();
lazy();
// 调用方法
Object result = methodProxy.invoke(object, args);
Long span = System.currentTimeMillis() - start;
System.out.println("共用时:" + span);
return result;
}
// 模拟延时
public void lazy() {
try {
int n = (int) new Random().nextInt(500);
Thread.sleep(n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试:
@org.junit.Test
public void test03() {
Math math3 = (Math) new CGLibProxy().getObject(new Math());
int n1 = 100, n2 = 5;
math3.add(n1, n2);
math3.sub(n1, n2);
math3.mut(n1, n2);
}
结果: