在不改变原有代码情况下,实现对原有代码的增强
案例
张三找律师打官司
静态代理
特点:代理类代码是写死的
优点:在不改变原有代码的情况下实现了对原有业务增强
缺点:一个目标类就需要一个代理类,不便于业务拓展
-
定义接口,规定核心业务(代理对象与目标对象做的是一样的事情)
//规定代理对象与目标对象之间所做的核心业务 public interface Speak { void say(); }
-
编写目标类(实现核心的业务)
public class 张三类 implements Speak{ @Override public void say() { System.out.println("我每天吃一顿饭,挨三顿打。我请求离婚"); } }
-
编写代理类(代理目标类--实现对目标的增强)
public class 律师类 implements Speak { // 创建目标类 private 张三类 张三; public 律师类(张三类 张三) { this.张三 = 张三; } @Override public void say() { System.out.println("巴拉巴拉...接下来由原告述说"); 张三.say();// 真正做核心业务还是目标对象,代理对象只是在目的对象的基础上增强 } }
-
测试
public static void main(String[] args) { 张三类 张三 = new 张三类(); 律师类 律师 = new 律师类(张三); // 真正的是代理类方法 律师.say(); }
动态代理
特点:代理类代码是动态生成
JDK动态代理
特点
-
基于接口实现(invocationhandler)
-
根据不同目标对象,生成不同代理对象
实现
-
定义接口,规定核心业务
public interface Speak { void say(); }
-
编写目标类
public class 张三类 implements Speak{ @Override public void say() { System.out.println("我每天吃一顿饭,挨三顿打。我请求离婚"); } }
-
编写JDK动态代理
public class JDKProxy implements InvocationHandler { // 目标对象 private Object 客户; public JDKProxy(Object obj) { this.客户 = obj; } // 增强代码写在invoke方法 // proxy:代理对象 // method:待增强的方法(接口中定义的方法) // args:待增强方法的参数 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("巴拉巴拉...接下来由原告述说"); // 用完目标对象方法时可能有返回 Object result = method.invoke(客户, args); return result; } }
-
生成代理对象
public static void main(String[] args) { 张三类 张三 = new 张三类(); // 调用Proxy类的newProxyInstance静态方法生成代理对象 Speak speak = (Speak) Proxy.newProxyInstance(张三.getClass().getClassLoader(), 张三.getClass().getInterfaces(), new JDKProxy(张三)); speak.say(); }
CGLIB动态代理
特点
基于类的继承实现(MethodInterceptor)
需要导包(cglib、asm)
实现
-
编写目标对象
public class 张三类{ public void say() { System.out.println("我每天吃一顿饭,挨三顿打。我请求离婚"); } }
-
编写代理类(实现MethodInterceptor)
public class MyProxy implements MethodInterceptor { // 目标对象 private Object target; public MyProxy(Object obj) { this.target = obj; } // intercept:编写增强的代码 // method:待增强的方法 // arg:待增强的方法需要的参数 @Override public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable { System.out.println("巴拉巴拉...接下来由原告述说"); Object result = method.invoke(target, arg2);//目标对象方法的返回值 如果为void 则为null return result; } }
-
获取代理对象
public static void main(String[] args) { 张三类 张三 = new 张三类(); MyProxy myProxy = new MyProxy(张三); // 第一个参数:目标对象类型 // 第二个参数:实现MethodInterceptor类的对象 张三类 create = (张三类) Enhancer.create(张三.getClass(), myProxy); create.say(); }
注意
代理类中默认将接口所有方法进行增强,若想对指定方法增强可自定义注解打标记,代理类中去判断标记
创建注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedAdd {}
方法中添加注解
public interface Speak {
@NeedAdd
void say();
int cry(int time);
}
根据方法是否存在注解进行使用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 判断是否存在注解标记
if(method.isAnnotationPresent(NeedAdd.class)) {
System.out.println("巴拉巴拉...接下来由原告述说");
// 用完目标对象方法时可能有返回
result = method.invoke(客户, args);
}else {
// 用完目标对象方法时可能有返回
result = method.invoke(target, args);
}
return result;
}