【spring系列】java动态代理

前言

​ 代理模式可以在访问目标对象的基础上,增强额外的功能。

​ 代理模式分为静态代理和动态代理,但是静态代理的代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护。动态代理便解决了此问题。

​ 动态代理在Spring,mybatis等框架中有广泛的应用。所以在了解框架源码前需要先了解动态代理。

1.java反射

​ 动态代理以java反射为基础。在了解动态代理前,需要先了解java反射机制。

​ Java 反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种 动态的获取信息 以及 动态调用对象的方法 的功能称为 java 的反射机制

​ 如上看着着实懵逼,看下代码:

​ 例如有一个UserInfo对象

public class UserInfo   {
    private Long id;
    private String name;

    public void init() throws Exception {
        System.out.println("这里是 UserInfo init");
	}
    public void init(String a) throws Exception {
        System.out.println("这里是 UserInfo init a:"+a);
    }
    public void init(String a,Integer b) throws Exception {
        System.out.println("这里是 UserInfo init a:"+a+"   b:"+b);
    }
}

那么创建此对象有以下几种方式:


    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        //普通方式进行创建
        UserInfo userInfo = new UserInfo();
        //通过反射机制进行创建
        Class userInfoClass = UserInfo.class;
        UserInfo userInfo1 = (UserInfo) userInfoClass.newInstance();
        //反射进行创建
        Class userInfoClass2= Class.forName("com.example.model.UserInfo");
        UserInfo userInfo2 = (UserInfo) userInfoClass2.newInstance();
    }

通过反射执行对象中的方法

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class userInfoClass = UserInfo.class;
        Object userinfo = userInfoClass.newInstance();
        // 执行init(String a) 方法
        Method init = userInfoClass.getMethod("init", new Class[]{String.class});
        init.invoke(userinfo,new Object[]{"123"});
        // 执行init(String a,Integer b)方法
        Method init2 = userInfoClass.getMethod("init", new Class[]{String.class,Integer.class});
        init2.invoke(userinfo,new Object[]{"123",123});
    }

输出:

这里是 UserInfo init a:123
这里是 UserInfo init a:123 b:123

详细可参考 java反射机制详解

java反射学习

2.java动态代理

java实现动态代理主要有两种,jdk动态代理和CGLIB动态代理。

jdk动态代理是jdk原生,不需要引用其他jar包,但是只能代理接口,如果需要对类进行动态代理则需要引用CLIGB动态代理。

2.1 jdk动态代理

Proxy提供了创建动态代理类和实例的静态方法

InvocationHandler是由代理实例的调用处理程序实现的接口。

代理者需要实现InvocationHandler接口

示例:

IUserInfoService.java

public interface IUserInfoService {
    void addUserInfo(UserInfo userInfo);
}

接口实现类UserInfoService.java

// 这里加上事务注解
@Transactional
public class UserInfoService implements IUserInfoService {
    @Override
    public void addUserInfo(UserInfo userInfo) {
        System.out.println("保存UserInfo");
    }
}

代理类ProxyHandler

public class ProxyHandler implements InvocationHandler {
    private Object object;
    public ProxyHandler(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法调用之前");
        //是否有开启事务注解
        boolean annotationPresent = object.getClass().isAnnotationPresent(Transactional.class);
        if(annotationPresent){
            System.out.println("开启事务");
        }
        Object invoke = method.invoke(object, args);
        if(annotationPresent){
            System.out.println("提交事务");
        }
        return invoke;
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        IUserInfoService userInfoService = new UserInfoService();
        //获取代理实现类
         // 由下面代理类可见,这里其实等于  IUserInfoService o = new UserServiceProxy()
        //然后UserServiceProxy这个对UserInfoService进行了代理。
        IUserInfoService o = (IUserInfoService)Proxy.newProxyInstance(userInfoService.getClass().getClassLoader(),userInfoService.getClass().getInterfaces(),new ProxyHandler(userInfoService));
		// 通过代理类实现方法,
       
        o.addUserInfo(new UserInfo());
        //保存代理类.class文件
        createClassFile(o.getClass(),"UserServiceProxy");
    }
    public static void createClassFile(Class clazz, String proxyName) {
        // 根据类信息和提供的代理类名称,生成字节码
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String paths = clazz.getResource("/").getPath();
        System.out.println(paths);
        FileOutputStream out = null;
        try {
            //保留到硬盘中
            out = new FileOutputStream(paths + proxyName + ".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代理类

public final class UserServiceProxy extends Proxy implements IUserInfoService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;

    public UserServiceProxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final UserInfo getUserInfoById(Long var1) throws  {
        try {
            return (UserInfo)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void addUserInfo(UserInfo var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.example.proxy.IUserInfoService").getMethod("getUserInfoById", new Class[]{Class.forName("java.lang.Long")});
            m4 = Class.forName("com.example.proxy.IUserInfoService").getMethod("addUserInfo", new Class[]{Class.forName("com.example.model.UserInfo")});
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

通过代理,java动态生成了UserServiceProxy类来对目标对象进行代理。

2.2 CLIGB动态代理

引入jar包

		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.3.0</version>
		</dependency>

被代理的类UserInfoService

public class UserInfoService implements IUserInfoService {
    @Override
    public void addUserInfo(UserInfo userInfo) {
        System.out.println("保存UserInfo");
    }
}

代理类,这里要实现MethodInterceptor接口,在方法执行的时候会调用intercept方法,这一点和jdk代理类似

public class CglibHandler implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行方法");
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("执行方法之后");
        return o1;
    }
}

接下来进行测试

public class Test {
    public static void main(String[] args) {
        //它是一个字节码增强器,可以用来为无接口的类创建代理 ,与JDK的Proxy类类似
        Enhancer enhancer = new Enhancer();
        // 设置被代理类
        enhancer.setSuperclass(UserInfoService.class);
        // 设置代理类
        enhancer.setCallback(new CglibHandler());
		//获取代理类
        UserInfoService hello = (UserInfoService)enhancer.create();
        // 执行方法,此会调用 代理类的intercept方法
        hello.addUserInfo(new UserInfo());
    }
}

输出:

执行方法
保存UserInfo
执行方法之后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叁滴水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值