Java jdk动态代理和cglib动态代理的使用介绍和区别
一·、首先,我们先介绍jdk动态代理:
jdk动态代理涉及到两个重要的类:
第一个: InvocationHandler ,在java.lang.reflect包下
import java.lang.reflect.InvocationHandler;
第二个:Proxy:是一个反射包下的工具类.它的作用就是创建jdk动态代理对象
先上一段简单的代码:
1、接口
//接口
public interface UserService {
//增加了一个用户
public void add();
//删除了一个用户
public void delete();
//修改了一个用户
public void update();
//查询了一个用户
public void query();
}
2、接口的实现类
//真实对象(目标对象)
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void query() {
System.out.println("查询一个用户");
}
}
3、代理类
//这个类自动生成代理类
public class ProxyInvocationHandler{
//生成得到代理对象
public Object getProxy(final Object target) {
/*
newProxyInstance()方法就是用来创建代理对象实例的
第一个参数:类加载器(一般放目标对象的类加载器)
第二个参数:是目标对象实现了的所有接口(代理对象实例也会实现)
第三个参数:InvocationHandler接口实现类( 这个接口,就是用来给目标方法实现额外功能的接口 ),这里用到了匿名内部类。
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler() {
/*
InvocationHandler接口实现类:
invoke方法是代理对象调用方法时,就会执行的方法(不管代理对象调用什么方法,都会执行invoke()方法), 要负责对原来的方法进行增强(在完成原来方法的功能上,做额外操作).
第一个参数: 是代理对象实例
第二个参数: 调用方法的反射对象实例
第三个参数: 调用方法时传递进来的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强 (在目标方法前做的额外操作)
log(method.getName());
/*
method.invoke()通过反射调用方法
第一个参数:方法的实例对象
第二个参数:方法调用时的参数
invoke方法的返回值就是代理调用的方法的返回值
*/
return method.invoke(target, args);
}
});
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
4、测试类
public class test {
public static void main(String[] args) {
//真实角色(目标对象)
UserServiceImpl userService = new UserServiceImpl();
//代理角色(代理对象)
ProxyInvocationHandler pro = new ProxyInvocationHandler();
//动态生成代理类
UserService proxy = (UserService) pro.getProxy(userService);
//调用删除方法方法
proxy.delete();
}
}
5、结果
执行了delete方法
删除了一个用户
代理类可以给很多的实体类一次性添加上这个日志操作,不用谢重复的日志代码。
二、其次介绍一下cglib动态代理:
1、代理类
public class cglibProxyFactory {
public Object cglibProxy(final Object target) {
//增强器 他生成一个cglib代理对象的实例
Enhancer enhancer = new Enhancer();
//指定要修改哪个目标对象的字节码程序
enhancer.setSuperclass(target.getClass());
//设置拦截器 ,跟InvocationHandler接口功能一样,是代理对象调用方法时就会执行的接口(对目标方法增强)
enhancer.setCallback(new MethodInterceptor() {
/*
只要代理对象调用就会执行intercept方法
第一个参数:代理对象实例
第二个参数:调用的方法的反射对象
第三个参数:调用方法时传递的参数
第四个参数:方法反射对象的代理对象
return 返回值是代理对象调用方法的返回值
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
log(method.getName());
return method.invoke(target, args);
}
});
//创建cglib代理对象的实例
return enhancer.create();
}
public void log(String msg) {
System.out.println("执行了" + msg + "方法");
}
}
2、测试类
public class test {
public static void main(String[] args) {
//真实角色(目标对象)
UserServiceImpl userService = new UserServiceImpl();
//代理角色(代理对象)
cglibProxyFactory cglibProxyFactory = new cglibProxyFactory();
//动态生成代理类
UserServiceImpl userService1 = (UserServiceImpl) cglibProxyFactory.cglibProxy(userService);
//调用方法
userService1.update();
}
}
3、结果
执行了update方法
修改了一个用户
三、两个动态代理的区别:
jdk动态代理他的缺点那就是目标对象如果没有实现接口那么他就无法使用,
cglib动态代理是目标对象没有实现接口他也可以实现,cglib是java字节码生成工具,他动态生成一个代理类的子类,子类重写被代理的类,在子类采用方法拦截技术拦截父类方法的调用。