Java中的代理方式包括静态代理和动态代理。 静态代理在编译期间就确定了代理对象,动态代理是在运行期间动态生成代理对象。动态代理包括cglib动态代理和jdk动态代理,在目标对象有接口的情况下,可以使用jdk动态代理或者cglib动态代理;如果目标对象没有接口,则无法使用jdk动态代理,只能使用cglib动态代理。下面是介绍分别实现cglib动态代理和jdk动态代理的简单例子。
下面的例子中, 要增强User类的talk()方法,在方法开始和结束时都输出当前的系统时间,但是不希望修改User类的代码,又因为User类没有实现接口,在这种情况下可以使用cglib动态代理实现。
代码逻辑:
- 创建User类,并且编写talk()方法;
- 创建User类的代理增强类,用于增强talk()方法的代码逻辑;
- 编写测试类,先创建一个User对象,然后通过增强类根据这个对象创建一个增强对象,最后执行增强对象的talk方法。
public class User {
public void talk(){
System.out.println("【交谈中。。。】");
}
}
- 执行Enhancer.create()方法,传入对应的参数,拿到一个增强后的对象;
- 重写MethodInterceptor()接口的 intercept()方法 编写具体的增强代码逻辑。
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class UserExtendByCglib {
public static Object getProxy(Object target){
/**
* Enhancer.create()方法, 参数1是对象的字节码, 参数2是拦截方法的程序的对象, 返回值是一个增强后的对象
*/
return Enhancer.create(target.getClass(), new MethodInterceptor() {
/**
* @param proxy 增强后的代理对象
* @param method 需要代理增强的方法
* @param args 需要代理增强的方法的参数
* @param methodProxy 增强后的代理对象的方法
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//增强代码逻辑1:开始时间
System.out.println(System.currentTimeMillis());
//执行最初的方法
Object result = method.invoke(target, args);
//增强代码逻辑2:结束时间
System.out.println(System.currentTimeMillis());
return result;
}
});
}
}
public class TestUser {
public static void main(String[] args) {
// 创建未被增强的对象
User user = new User();
// 通过代理对象, 对初始对象增强, 然后得到一个增强对象
User userProxy = (User) UserExtendByCglib.getProxy(user);
// 执行增强后的方法
userProxy.talk();
}
}
在下面的例子中,想要对Student类的talk方法增强,talk是Student实现Talk接口重写后的方法,这种情况可以使用jdk动态代理实现。
代码逻辑:
- 定义一个Talk接口,其中包含talk()方法;
- 创建Student类,实现Talk接口,重写talk()方法;
- 创建Talk接口的代理增强类,用于增强talk()方法的代码逻辑;
- 编写测试类,先创建一个Student对象,然后通过增强类根据这个对象创建一个增强对象,最后执行增强对象的talk()方法。
public interface Talk {
void talk();
}
public class Student implements Talk{
@Override
public void talk() {
System.out.println("【交谈中。。。】");
}
}
- 通过执行Proxy.newProxyInstance()方法拿到一个代理对象;
- 重写接口InvocationHandler的invoke()方法编写具体的增强逻辑。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TalkProxyByJdk {
public static Object getProxy(Object target){
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
/**
* @param proxy 增强后的代理对象
* @param method 需要代理增强的方法
* @param args 需要代理增强的方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始说话的时间:"+System.currentTimeMillis());
Object result = method.invoke(target, args);
System.out.println("停止说话的时间:"+System.currentTimeMillis());
return result;
}
}
);
return proxy;
}
}
import java.lang.reflect.Proxy;
public class TestJdkProxy {
public static void main(String[] args) {
// 创建初始对象
Talk student = new Student();
// 创建代理对象
Talk proxy = (Talk) TalkProxyByJdk2.getProxy(student);
// 执行代理对象的增强方法
proxy.talk();
}
}