1.代理
代理类相比于目标类,多做了一些工作,可以看做是对目标类的增强。
2.静态代理
代理类和目标类实现同一个接口,然后在创建代理对象时,通过构造器塞入一个目标对象。在代理对象的方法中调用目标对象的方法,在调用目标方法的前后可以执行自定义的方法,实现对目标对象方法的增强。
优点:在编译器实现代理,性能更好。
缺点:需要手动为每一个目标类编写对应的代理类,代码规模增加太快。
3.动态代理
代理类通过java.lang.reflect.Proxy获取代理对象;实现java.lang.reflect.InvocationHandler接口,在invoke() 方法中实现对目标对象方法的增强。
优点:只需要写一个代理类,就可以代理不同的目标类。
缺点:运行期实现代理,性能也比静态代理更差一点。
例:
接口:
public interface MathInterface {
int getSum(int... nums);
}
目标类:
public class MathInterfaceImpl implements MathInterface {
@Override
public int getSum(int... nums) {
int sum = 0;
StringBuilder sb = new StringBuilder();
for (int i : nums) {
sum += i;
sb.append(i).append("+");
}
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
sb.append("=").append(sum);
}
System.out.println(sb.toString());
return sum;
}
}
静态代理类:
import java.util.Arrays;
public class StaticProxy implements MathInterface {
private MathInterface proxy;
StaticProxy(MathInterface proxy) {
this.proxy = proxy;
}
@Override
public int getSum(int... nums) {
System.out.println("静态代理类前置打印:\n入参:" + Arrays.toString(nums));
int sum = proxy.getSum(nums);
System.out.println("静态代理类后置打印:\n运算结果:" + sum);
return sum;
}
}
动态代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
private Object proxy;
private ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public Object getInstance(Object proxy) {
this.proxy = proxy;
return Proxy.newProxyInstance(this.proxy.getClass().getClassLoader(), this.proxy.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
if (beforeInvoke(proxy, method, args)) {
result = method.invoke(this.proxy, args);
}
afterInvoke(proxy, method, args, result);
return result;
}
private boolean beforeInvoke(Object proxy, Method method, Object[] args) {
if (method == null) {
return false;
}
long startTime = System.currentTimeMillis();
threadLocal.set(startTime);
System.out.println("动态代理前置打印:\n方法:" + method + "\t开始执行时间:" + startTime + "\t线程:" + Thread.currentThread().getName());
return true;
}
private void afterInvoke(Object proxy, Method method, Object[] args, Object result) {
System.out.println("动态代理类后置打印:\n结果:" + result.toString() + "\t耗时:" + (System.currentTimeMillis() - threadLocal.get()) + "ms" + "\t线程:" + Thread.currentThread().getName());
// 这需要手动remove,不然会有内存泄露问题
threadLocal.remove();
}
}
测试类:
public class ProxyDemo {
public static void main(String[] args) throws Exception {
// 静态代理
MathInterfaceImpl impl = new MathInterfaceImpl();
MathInterface obj = new StaticProxy(impl);
obj.getSum(1, 2, 3, 45, 25, 2);
System.out.println("\n\n\n\n");
// 动态代理
DynamicProxy proxy = new DynamicProxy();
MathInterface sub = (MathInterface) proxy.getInstance(new MathInterfaceImpl());
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
sub.getSum(1, 23, 62, 85, 28, 525, 5);
}
}).start();
}
}
}