Jdk动态代理与Cglib动态代理的简单使用
程序员文章站
2024-01-26 15:04:10
...
基本介绍
目前Java的动态代理主要分为jdk自带的动态代理java.lang.reflect.Proxy 和 谷歌的cglib
JDK动态代理介绍:
- 生成的代理对象不需要实现接口,但是目标对象要实现接口,否则无法使用动态代理,因为在转化过程中会抛错
- 代理对象的生成是利用JDK的api,动态的内存中构建代理对象
- 动态代理也叫:JDK代理、接口代理
JDK中生成的代理对象api
- 代理类包:java.lang.reflect.Proxy
- jdk实现代理只需要使用Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
应用一:动态代理实现方法侵入
举例:有一个动物接口,接口中有两个方法,然后很多类都需要实现它并且复写这两个方法,但是我们想要在执行这个方法之前执行下自己自定义的一个方法,怎么做?那么这就可以利用动态代理去实现。
1.首先定义一个接口类,并且内部类dog去实现这个方法
package Aop.JDKProxy;
/**
* @author Heian
* @time 19/03/26 8:32
*/
public interface Animals {
void run();
String eat();
static class Dog implements Animals{
@Override
public void run() {
System.out.println ("狗开始跑");
}
@Override
public String eat() {
System.out.println ("狗开始吃");
return "吃";
}
}
}
2.在定义一个测试类,当然因为要用到动态代理,所以要传入InvocationHandler这个类,并且复写这个类的invoke(Object proxy, Method method, Object[] args),此方法代理块里就可以填写的你的动态代理的逻辑了。
package Aop.JDKProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Heian
* @time 19/03/26 8:35
* 用途:
*/
public class MyProxy implements InvocationHandler {
//返回的代理类
private Object obj;
/**
* @proxy 被代理的对象
* @method 要调用的方法
* @agrs 方法调用所需参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//注入需要插入的方法
command1();
//执行被代理对象的方法、如果有返回值则赋值给ret
Object ret = method.invoke (obj,args);//Objetc obj = obj.方法(agrs); 接口方法返回的对象,
//注入需要插入的方法
command2();
return ret;
}
//绑定委托对象并返回一个代理类(代理类对象无需实现接口)
public Object creatProxyInstance(Object object){
this.obj = object;
Object ob = Proxy.newProxyInstance (obj.getClass ().getClassLoader (),obj.getClass ().getInterfaces (),this);
return ob;
}
//定义要插入的方法
private void command1(){
System.out.println ("主人发出命令");
}
private void command2(){
System.out.println ("主人给出奖励");
}
public static void main(String[] args) {
MyProxy myProxy = new MyProxy ();
Animals dogAnimals = (Animals) myProxy.creatProxyInstance (new Animals.Dog ());
//Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to Aop.JDKProxy.Animals
dogAnimals.run ();
dogAnimals.eat ();
}
}
需要注意的就是在调用 myProxy.creatProxyInstance (目标类),目标类必须实现接口否则会抛出类转化异常,因为返回的是一个代理类对象 aaa@qq.com。
备注:
Object ob = method.invoke(obj,args);比如我ob类有一个变量List,存在get方法
public List getList(){return list};
现在利用反射去调这个get方法,其中返回的就是是List类型,但是你传入的对象是一个ArrayList,此时就会抛出NoSuchMethodException,所以在利用发射去调用方法时,最好使用接口
应用二:动态代理实现事物(伪代码)
//接口
public interface IUserService {
void saveUser();
}
//实现子类
public class UserServiceImpl implements IUserService {
@Override
public void saveUser() {
System.out.println("保存用户信息");
}
}
package Aop.JDKProxy2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理类
public class DynamicProxy implements InvocationHandler {
private Object targetObj;//相当于一个媒介
public DynamicProxy(Object targetObj){
this.targetObj = targetObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
try {
startTranstraction();
obj = method.invoke(targetObj, args);
}catch (Exception e){
rollback();
}finally {
conmmitTranstraction();
}
return obj;
}
public void startTranstraction(){
System.out.println("开启事物");
}
public void conmmitTranstraction(){
System.out.println("提交事物");
}
public void rollback(){
System.out.println("回滚事物");
}
public static void main(String[] args) {
UserServiceImpl target = new UserServiceImpl();
DynamicProxy dynamicProxy = new DynamicProxy(target);
IUserService proxy = (IUserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),dynamicProxy);
proxy.saveUser();
}
}
开启事物
保存用户信息
提交事物