本文说明:在学习《Java EE互联网轻量级框架整合开发》此书时,里面提到了几种设计模式,我在学习这几种设计模式时写了笔记,放上来让大家共同学习,如果有错误,望指出。
本文章由两部分组成:
JDK动态代理的基本概念+关键代码讲解+完整例子
CGLIB动态代理的完整例子
JDK动态代理的基本概念+关键代码讲解+完整例子
动态代理主要用来向已经实现的方法或逻辑的前后动态加入逻辑,比如日志等,Spring中就用到了动态代理。动态代理主要有两种,分别是JDK动态代理和CGLIB动态代理。两者的唯一区别是需要接口和不需接口。其中,JDK需要接口,CGLIB不需接口。二者很相似,掌握其中之一便能掌握另一个。
基本概念+关键代码讲解
基本构成:目标接口,目标类(继承目标接口),JDK动态代理逻辑实现类,测试类
【目标接口和类】:可能被插入逻辑的代码;
【JDK动态代理逻辑实现类】:关键类;
【测试类】:测试动态代理已经实现的代码。
下面主要讲讲【JDK动态代理逻辑实现类】。
此类首先需要实现 java.lang.reflect 包里面的接口 InvocationHandler,进而实现(重写)方法 invoke()。实现方法invoke()有什么作用?它其实就是实现对目标类的方法前后插入动态逻辑的一串代码。使用时,得先用目标类作为参数得到代理对象proxy,当我们通过proxy调用目标类的方法时,JDK自动帮我们寻找到此重写方法invoke的逻辑进行相应代替。当然为了不覆盖原有的目标类方法,需要我们在invoke()方法里面调用原有方法,这时就用到了反射。
上一段话说明,我们需要在这个类里面实现两个方法,第一个方法是使用目标类得到代理对象proxy(我们称为bind方法),第二个方法是重写invoke()方法。
实现bind()方法非常简单,我们清楚输入是目标类,输出是代理proxy,这个proxy就是 java.lang.reflect 包的 Proxy类,如何生成Proxy对象?需要调用 Proxy.newInstance()方法,参数如下:
//参数说明:
//target就是我们的目标类对象
//this就是重写了invoke()方法的类的对象,在这里就是【JDK动态代理逻辑实现类】的对象
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
所以bind()方法的完整代码为:
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
重写invoke()方法前,我们先看看IDEA自动生成的invoke()方法的参数是什么:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}
前面已经说过invoke得包含原有逻辑,可以看到这里有个方法参数method以及它对应的参数列表args,通过这两个对象加上我们在此类的bind()方法得到的对象target,我们可以用反射(反射参照“设计模式——反射”这一篇)得到原有方法逻辑,核心代码如下:
Object returnObj = method.invoke(target, args);
所以invoke()方法全部代码如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入逻辑方法之前");
System.out.println("在调度真实对象之前的服务");
Object returnObj = method.invoke(target, args);
System.out.println("在调度真实对象之后的服务");
return returnObj;
}
实现完这个类后,使用时,new一个此类对象,然后通过它调用bind方法,传入target对象,得到proxy对象再Cast为目标接口对象,通过目标接口对象调用方法,运行可知已经实现了JDK动态代理。完整代码如下。
完整代码
//包括1个接口3个类,分别为目标接口,目标类,关键类,测试类
//目标接口
package com.amiao.design_pattern.dynamic_proxy.jdk;
public interface HelloWorld {
public void sayHelloWorld();
}
//目标类
package com.amiao.design_pattern.dynamic_proxy.jdk;
public class HelloWorldImpl implements HelloWorld {
public void sayHelloWorld() {
System.out.println("Hello World");
}
}
//关键类
package com.amiao.design_pattern.dynamic_proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyExample implements InvocationHandler {
private Object target = null;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入逻辑方法之前");
System.out.println("在调度真实对象之前的服务");
Object returnObj = method.invoke(target, args);
System.out.println("在调度真实对象之后的服务");
return returnObj;
}
}
//测试类
package com.amiao.design_pattern.dynamic_proxy.jdk;
public class TestMain {
public static void main(String args[]) {
JdkProxyExample jdk = new JdkProxyExample();
HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
proxy.sayHelloWorld();
}
}
/*
* 测试结果
* 进入逻辑方法之前
* 在调度真实对象之前的服务
* Hello World
* 在调度真实对象之后的服务
* */
CGLIB动态代理的完整例子
//包括3个类,目标类,CGLIB动态代理逻辑实现关键类,测试类
//目标类
package com.amiao.design_pattern.dynamic_proxy.cglib;
public class ReflectTarget {
public void saySomething() {
System.out.println("Hello, I'm reflect target");
}
}
//关键类
package com.amiao.design_pattern.dynamic_proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyExample implements MethodInterceptor {
public Object getProxy(Class cls) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("进入逻辑方法之前");
System.out.println("在调度真实对象之前的服务");
Object returnObj = methodProxy.invokeSuper(proxy, args);
System.out.println("在调度真实对象之后的服务");
return returnObj;
}
}
//测试类
package com.amiao.design_pattern.dynamic_proxy.cglib;
public class TestMain {
public static void main(String args[]) {
CglibProxyExample cglib = new CglibProxyExample();
ReflectTarget proxy = (ReflectTarget) cglib.getProxy(ReflectTarget.class);
proxy.saySomething();
}
}
/*
* 测试结果
* 进入逻辑方法之前
* 在调度真实对象之前的服务
* Hello, I'm reflect target
* 在调度真实对象之后的服务
* */