JAVASE-14 静态代理与动态代理

背景

最近在翻阅Spring和Mybatis事务相关源码时发现代码中大量使用动态代理,且早前开启的JAVASE专题中代理部分的文章一直没有补充,趁着容器化和事务专题的空隙补充一下。
本文主题内容是代理:包括静态代理和动态代理,其中动态代理是重点,该部分包括JDK代理和CGLIB代理,以下通过案例的方式进行介绍。

1.代理设计模式

代理设计模式的核心是分离代理对象与真实被调用的对象,降低系统的耦合性。一方面可以起到保护被代理对象的作用,另一方面可以实现对既有功能的增强。
代理按照实现可以分为:静态代理和动态代理,静态代理在编译期生成,动态代理在程序运行的过程中生成。静态代理比较简单,需要为每个接口类编写一个代理类;当接口类很多、代理的处理逻辑相同的场景或者作为框架时(不可知被代理类场景),静态代理不再适用,此时可以使用动态代理代替。
比如:一个接口中有N个方法,需要对每个方法添加事务处理机制,此时需要重复N次与业务无关的代码,使得代码显得肿胀😭。这种场景使用1个动态代理就能实现上述功能,且把业务和业务无关的重复代码进行分割👍;分离变化与不变量、降低代码重复度可以提高代码的可读性和可维护性。
另外,Java提倡面向接口编程,但并非所有类都基于接口,因此Java提供了两种类型的动态代理:CGLIB代理和JDK代理。其中:JDK代理接口类,而CGLIB可以代理非接口类。以下通过案例的方式对上述三种代理模式分别介绍。

2.静态代理

静态代理基于接口,要求代理类和被代理类(后续使用目标类表示🥸)属于同一接口的实现类。在代理类中实现接口中定义的方法,并在方法实现体中调用目标类的方法,从而实现代理功能。
以下通过案例进行介绍:

// 接口类
public interface AccountDao {
    void reduce(int cost);
}

// 目标类
public class AccountDaoImpl implements AccountDao {
    @Override
    public void reduce(int cost) {
        System.out.println("cost " + cost + " yuan.");
        // ... database operation
    }
}

// 代理类
public class AccountDaoProxy implements AccountDao {
    private AccountDao target;

    public AccountDaoProxy(AccountDao target) {
        this.target = target;
    }

    @Override
    public void reduce(int cost) {
    	//...
    	connection.setAutoCommit(false);
        try {
        	target.reduce(cost);
        	connection.commit();
		} catch(Exception e) {
			connection.rollback();
		} finally {
			//...
		}
    }
}

// demo start
public class Application {
    public static void main(String[] args) {
        AccountDao accountDao = new AccountDaoImpl();
        AccountDaoProxy accountProxy = new AccountDaoProxy(accountDao);
        accountProxy.reduce(100);
    }
}

上述案例中代理类AccountDaoProxy对目标类AccountDaoImpl的功能进行了增强,为其添加了事务机制。当AccountDao中新增方法是,需要再次添加重复的事务处理代码,较为繁琐;此时可以借助动态代理实现。

3.JDK动态代理

public class ProxyFactory {
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object build() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new Interceptor());
    }

    class Interceptor implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before...");
            method.invoke(target, args);
            System.out.println("after...");
            return null;
        }
    }
}

public class Application {
    public static void main(String[] args) {
        Printer printer = new PrinterImpl();
        ProxyFactory proxyFactory = new ProxyFactory(printer);
        Printer printer2 = (Printer)proxyFactory.build();
        printer2.print();
        printer2.print("nameB","ageB");
    }
}

4.CGLIBd动态代理

public class Printer {
    public void print() {
        System.out.println("print here!");
    }

    public void print(String name, String age) {
        System.out.println("print here! name is: " + name + "; " + "age is:" + age);
    }
}

public class ProxyFactory implements MethodInterceptor {
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object build() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object arg0, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before...");
        method.invoke(target,args);
        System.out.println("after...");
        return null;
    }
}

public class Application {
    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new Printer());
        Printer printer = (Printer)proxyFactory.build();
        printer.print();
        printer.print("nameA","ageA");
    }
}

todo: 明天补充

5.应用场景
6.AOP和ASPECT

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值