动态代理
一、JDK
JDK实现动态代理类,被代理的类需实现接口。自动生成的代理类也会实现该接口。
定义接口
package com.test;
public interface User {
public void talk();
public void run();
}
被代理类
package com.test;
public class UserImpl implements User{
@Override
public void talk() {
System.out.println("i am talking");
}
@Override
public void run() {
System.out.println("i am running");
}
}
创建请求处理类(实现InvocationHandler接口)
package com.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler{
//关联代理对象
private Object target;
//参数为空的构造方法
MyInvocationHandler(){
super();
}
//通过构造函数的方式
MyInvocationHandler(Object target){
this.target=target;
}
/*proxy : 生成的代理类
method : 代理方法对象
args : 代理方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置逻辑
System.out.println("before method");
//代理执行所需方法
Object result =method.invoke(target, args);
//后置逻辑
System.out.println("after method");
//方法执行返回值
return result;
}
}
这里顺便说一下类与类之间的几种关系:
关系 | java中表现形式 | 区分 |
---|---|---|
泛化 | 继承 | ” extends “ |
实现 | 接口实现 | ” implements “ |
依赖 | 类方法中的局部变量 | ” uses a “ |
关联 | 类成员变量 | ” has “ |
聚合 | 类成员变量 | ” owns a “ |
组合 | 类成员变量 | ” is a part of” |
关联、聚合、组合,变现形式一样,仅仅是逻辑上的区别。而上面的MyInvocationHandler类关联了Object 被代理对象。这是代理模式的核心之一。
测试
package com.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import org.junit.Test;
public class TestInvocation {
/**
*
* @throws NoSuchMethodException
* @throws SecurityException
* 使用jdk自带的动态代理api
*/
@Test
public void testInvocation() throws NoSuchMethodException, SecurityException{
User user = new UserImpl();
InvocationHandler invocationhandler = new MyInvocationHandler(user);
//三个参数分别为:类加载器,接口类,请求处理类
User userproxy=(User)Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), invocationhandler);
userproxy.talk();
}
}
运行结果
before method
i am talking
after method
二、Cglib
cglib直接生成二进制码。被代理类不需要实现接口。所创建的动态代理对象继承了被代理类。spring和mybatis框架都用到了cglib。
准备
cglib由github托管
下载jar包
cglib-nodep-3.2.4.jar (含asm.jar)
不推荐下载cglib-3.2.4.jar (不含asm.jar,而asm.jar 为cglib依赖包)
被代理类
package com.test2;
/*
* cglib 不需要接口
*/
public class UserImpl{
public void talk() {
System.out.println("i am talking");
}
public void run() {
System.out.println("i am running");
}
}
创建方法拦截器类
package com.test2;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MyProxy implements MethodInterceptor{
private Enhancer e = new Enhancer();
public Object newInstance(Class<?> clazz){
//传入被代理类
e.setSuperclass(clazz);
//传入方法拦截器
e.setCallback(this);
//生成代理类
return e.create();
}
/**
* obj : 被代理对象
* method : 被代理类的方法对象
* args : 被代理类的方法参数对象
* proxy : 方法代理对象
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before ----");
Object result =proxy.invokeSuper(obj, args);
System.out.println("after ----");
return result;
}
}
测试
package com.test2;
import org.junit.Test;
/**
* <p> Title:MyProxyTest.java</p>
* <p> Description:cglib 实现动态代理 </p>
* @author
* @date
* @version 1.0
*/
public class MyProxyTest {
@Test
public void test1(){
MyProxy proxy = new MyProxy();
//直接生成代理类
UserImpl userproxy=(UserImpl)proxy.newInstance(UserImpl.class);
userproxy.run();
}
}
结果
before ----
i am running
after ----