动态代理实现:
jdk动态代理
cglib动态代理
注意:动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成
JDK动态代理
- 利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口定义代理类的实现。
创建抽象的委托者
- UserService.java
/**
* 委托类和代理类的接口
* @author LingDu
*/
public interface UserService {
public void insert();
}
具体的委托者
- UserServiceImp.java
/**
* 委托类
* @author LingDu
*/
public class UserServiceImp implements UserService {
@Override
public void insert() {
System.out.println("insert success");
}
}
具体的代理者
- MyInvocatioHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口定义代理类的实现。
* @author LingDu
*/
public class MyInvocatioHandler implements InvocationHandler {
private Object obj;
public MyInvocatioHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("begin...");
Object result = method.invoke(obj, args);
System.out.println("end...");
return result;//返回代理对象
}
//生成代理对象
public Object getProxyObj() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?>[] interfaces = obj.getClass().getInterfaces();
return Proxy.newProxyInstance(loader, interfaces, this);
}
}
代理类实现InvocationHandler接口重写invoke(Object proxy, Method method, Object[] args)方法
创建代理对象实例必须使用Proxy类中的newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )方法
newProxyInstance完整的写法如下:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:
ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的
Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
测试
UserService userServiceProxy = (UserService) new MyInvocatioHandler(new UserServiceImp()).getProxyObj();
userServiceProxy.insert();
JDK动态代理总结
使用内置的Proxy实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。如果项目中有些类没有实现接口,则不应该为了实现动态代理而刻意去抽出一些没有实例意义的接口,通过cglib可以解决该问题。
cglib动态代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
引入cglib所需的jar包
<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.1</version>
</dependency>
- 如果去Maven资源库下载的话注意一定要下载:cglib-nodep 的版本才可以用
创建抽象的委托者
- UserService.java
/**
* 委托类和代理类的接口
* @author LingDu
*/
public interface UserService {
public void insert();
}
具体的委托者
- UserServiceImp.java
/**
* 委托类
* @author LingDu
*/
public class UserServiceImp implements UserService {
@Override
public void insert() {
System.out.println("insert success");
}
}
创建代理者
- CglibProxy.java
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 实现MethodInterceptor接口重写intercept()方法
* @author LingDu
*/
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("begin...");
Object result = methodProxy.invoke(target, args);
System.out.println("end...");
return result;// 返回代理对象
}
public Object getProxyObj(){
//增强器,动态代码生成器
Enhancer enhancer = new Enhancer();
//回调方法
enhancer.setCallback(this);
//设置父类
enhancer.setSuperclass(target.getClass());
//返回对象
return enhancer.create();
}
}
测试
UserService userService = (UserService) new CglibProxy(new UserServiceImp()).getProxyObj();
userService.insert();
注意:使用cglib可以实现动态代理,即使被代理的类没有实现接口,但被代理的类必须不是final类。
延伸
在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理