设计模式--代理模式

代理模式应用场景

SpringAOP、日志记录,性能统计,安全控制,事务处理,异常处理等等。  

代理的分类

  • 静态代理(静态定义代理类)
  • 动态代理(动态生成代理类)

Jdk自带动态代理

Cglib 、javaassist(字节码操作库)

 

静态代理

什么是静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

静态代理代码

public interface IUserDao {
    void save();
}
public class UserDao implements IUserDao {
    public void save() {
        System.out.println("已经保存数据...");
    }
}

代理类

public class UserDaoProxy implements IUserDao {
    private IUserDao target;
​
    public UserDaoProxy(IUserDao iuserDao) {
        this.target = iuserDao;
    }
​
    public void save() {
        System.out.println("开启事物...");
        target.save();
        System.out.println("关闭事物...");
    }
​
}

JDK动态代理

概念

在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。

InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。
 

JDK动态代理实现的原理

首先Jdk的动态代理实现方法是依赖于接口的,首先使用接口来定义好操作的规范。然后通过Proxy类产生的代理对象调用被代理对象的操作,而这个操作又被分发给InvocationHandler接口的 invoke方法具体执行

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

 此方法的参数含义如下
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表当前执行方法传入的实参
返回值:表示当前执行方法的返回值

定义抽象方法

public interface Star {
    void sing();
}

抽象方法具体实现

public class RealStar implements Star {
    @Override
    public void sing() {
        System.out.println("真正明星唱歌");
    }
}

代理类创建

public class DynamicProxy implements InvocationHandler{
    private Star star;
    public DynamicProxy(Star star) {
        super();
        this.star = star;
    }

    /**代理增强方法**/
    protected void sellTicket() {
        System.out.println("代理卖票");
    }
    /**代理增强方法**/
    protected void collectMoney() {
        System.out.println("代理收钱");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk动态代理");
        sellTicket();
        method.invoke(star,args);
        collectMoney();
        return null;
    }

    public static void main(String[] args){
        Star star=new RealStar();
        Star proxy= (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class},new DynamicProxy(star));
        proxy.sing();

    }
}

测试结果

jdk动态代理
代理卖票
真正明星唱歌
代理收钱

CGlib动态代理

由于JDK只能针对实现了接口的类做动态代理,而不能对没有实现接口的类做动态代理,所以cgLib横空出世!CGLib(Code Generation Library)是一个强大、高性能的Code生成类库,它可以在程序运行期间动态扩展类或接口,它的底层是使用java字节码操作框架ASM实现。

1 引入cgLib 库
cglib-nodep-3.2.6.jar:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类.

2 定义业务类,被代理的类没有实现任何接口

public class Frank {
   public void submit(String proof) {
       System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
   }
   public void defend() {
       System.out.println(String.format("铁证如山,%s还Frank血汗钱","马旭"));
   }
}

 3 定义拦截器,在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。

public class cgLibDynProxyLawyer implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        if (method.getName().equals("submit"))
            System.out.println("案件提交成功,证据如下:"+ Arrays.asList(params));
        Object result = methodProxy.invokeSuper(o, params);
        return result;
    }
}

 4定义动态代理工厂,生成动态代理

public class ProxyFactory {
    public static Object getGcLibDynProxy(Object target){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new cgLibDynProxyLawyer());
        Object targetProxy= enhancer.create();
        return targetProxy;
    }
}

5客户端调用

  public static void main(String[] args) {
        Frank cProxy= (Frank) ProxyFactory.getGcLibDynProxy(new Frank());
        cProxy.submit("工资流水在此");
        cProxy.defend();
    }
案件提交成功,证据如下:[工资流水在此]
老板欠薪跑路,证据如下:工资流水在此
铁证如山,马旭还Frank血汗钱

 

cgLib的动态代理原理

CGLIB原理动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快

CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

CGLIB缺点:对于final方法,无法进行代理。

 

静态代理

抽象角色

public interface Star {
    void sing();
}
public class RealStar implements Star{
    @Override
    public void sing() {
        System.out.println("真正明星唱歌");
    }
}
/**
 * 静态代理:
 *     被代理类含有接口和具体实现类;
 *     代理类实现被代理接口,并含有被代理接口属性、相应属性构造器
 *
 * Created by Administrator on 2019/2/24 0024.
 */
public  class ProxyStar implements Star{
    private Star star;

    public ProxyStar(Star star) {
        this.star = star;
    }

    @Override
    public void sing() {
        this.sellTicket();
        star.sing();
        this.collectMoney();
    }

    private void sellTicket() {
        System.out.println("经纪人卖票");
    }

    private void collectMoney() {
        System.out.println("经纪人收钱");
    }

    public static void main(String[] args){
        ProxyStar proxyStar=new ProxyStar(new RealStar());
        proxyStar.sing();
    }
}

静态代理和动态代理的区别

静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。

动态:在程序运行时运用反射机制动态创建而成。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值