元月's blog 元月's blog
首页
  • 基础
  • 并发编程
  • JVM
  • Spring
  • Redis篇
  • Nginx篇
  • Kafka篇
  • Otter篇
  • Shardingsphere篇
  • 设计模式
  • MySQL
  • Oracle
  • 基础
  • 操作系统
  • 网络
  • 数据结构
  • 技术文档
  • Git常用命令
  • GitHub技巧
  • 博客搭建
  • 开发工具
更多

元月

临渊羡鱼,不如退而结网
首页
  • 基础
  • 并发编程
  • JVM
  • Spring
  • Redis篇
  • Nginx篇
  • Kafka篇
  • Otter篇
  • Shardingsphere篇
  • 设计模式
  • MySQL
  • Oracle
  • 基础
  • 操作系统
  • 网络
  • 数据结构
  • 技术文档
  • Git常用命令
  • GitHub技巧
  • 博客搭建
  • 开发工具
更多
  • 设计模式

    • 设计模式简介
    • 设计模式之单例模式
    • 设计模式之工厂模式
    • 设计模式之原型模式
    • 设计模式之建造者模式
    • 设计模式之适配器模式
    • 设计模式之桥接模式
    • 设计模式之组合模式
    • 设计模式之装饰器模式
    • 设计模式之外观模式
    • 设计模式之享元模式
    • 设计模式之代理模式
      • 一、简介
      • 二、实现方式
        • 1、静态代理
        • 2、动态代理
        • 2.1、JDK动态代理
        • 2.2、Cglib动态代理,也叫作子类代理
      • 三、应用场景
        • 1、Spring AOP底层实现
      • 四、思维导图
    • 设计模式之责任链模式
    • 设计模式之命令模式
    • 设计模式之解释器模式
    • 设计模式之迭代器模式
    • 设计模式之中介者模式
    • 设计模式之备忘录模式
    • 设计模式之观察者模式
    • 设计模式之状态模式
    • 设计模式之策略模式
    • 设计模式之模版模式
    • 设计模式之访问者模式
    • 设计模式辨析篇
  • 高可用

  • 系统设计
  • 设计模式
元月
2022-08-16
目录

设计模式之代理模式

# 设计模式之代理模式

# 一、简介

将一个对象包装起来以控制和管理对对象的访问

# 二、实现方式

# 1、静态代理

代理类需要自己编写代码

我们以找房租房为例,我们一般找中介找房子,这里中介就是代理者。代码示例:

  • 租房方法
public interface IRentHouse {
    void rentHouse();
}
1
2
3
  • 定义租房的实现类
public class RentHouse implements IRentHouse {
    @Override
    public void rentHouse() {
        System.out.println("租了一间房子。。。");
    }
}
1
2
3
4
5
6
  • 代理
public class IntermediaryProxy implements IRentHouse {
    private IRentHouse rentHouse;
    public IntermediaryProxy(IRentHouse irentHouse){
        rentHouse = irentHouse;
    }
    @Override
    public void rentHouse() {
        System.out.println("交中介费");
        rentHouse.rentHouse();
        System.out.println("中介负责维修管理");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
  • 测试类
public static void main(String[] args){
        //定义租房
        IRentHouse rentHouse = new RentHouse();
        //定义中介
        IRentHouse intermediary = new IntermediaryProxy(rentHouse);
        //中介租房
        intermediary.rentHouse();
    }
1
2
3
4
5
6
7
8

# 2、动态代理

# 2.1、JDK动态代理

主要是利用反射机制生成一个实现代理接口的类。目标对象一定要实现接口,否则不能使用JDK代理

JDK动态代理的实现需要使用java.lang.reflect.Proxy.newProxyInstance方法,这个方法有三个参数:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
1

ClassLoader loader:目标对象使用的类加载器

Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型

InvocationHandler h:调用处理器,在执行目标对象的方法时,会触发调用InvocationHandler类的invoke()方法,会把当前执行目标对象的方法作为参数传进来

代码示例:

/**
 * 代理工厂类:ProxyFactory.java
 * 创建动态代理对象
 * 动态代理不需要实现接口,但是需要指定接口类型
 */
public class ProxyFactory{
    private Object target;//维护一个目标对象
    public ProxyFactory(Object target){
        this.target=target;
    }
    public Object getProxyInstance(){//给目标对象生成代理对象
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开始事务2");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事务2");
                        return returnValue;
                    }
                }
        );
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void main(String[] args) {
        IUserDao target = new UserDao();// 目标对象
        // 【原始的类型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());
        // 给目标对象,创建代理对象
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        // class $Proxy0   内存中动态生成的代理对象
        System.out.println(proxy.getClass());
        proxy.save(); // 执行方法   【代理对象】
 }
1
2
3
4
5
6
7
8
9
10
# 2.2、Cglib动态代理,也叫作子类代理

通过继承目标类,创建它的子类,在子类中重写父类的方法,来实现功能的修改

  • 实现方法

​ 1.需要引入cglib的jar文件,但是在Spring的核心包中已经包括了Cglib功能,所以直接引入spring-core-3.2.5.jar即可.

​ 2.引入功能包后,就可以在内存中动态构建子类

​ 3.目标类不能为final,否则会报错

​ 4.目标类的方法不能为final/static,否则不会被拦截,即不会执行目标对象额外的业务方法.

  • 代码示例
/**
 * 目标对象,没有实现任何接口
 */
public class UserDao {

    public void save() {
        System.out.println("----已经保存数据!----");
    }
}
1
2
3
4
5
6
7
8
9
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * Cglib子类代理工厂
 * 对UserDao在内存中动态构建一个子类对象
 */
public class ProxyFactory implements MethodInterceptor {
    //维护目标对象
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        Enhancer en = new Enhancer();//1.工具类
        en.setSuperclass(target.getClass());//2.设置父类
        en.setCallback(this);//3.设置回调函数
        return en.create();//4.创建子类(代理对象)
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");
        Object returnValue = method.invoke(target, args);//执行目标对象的方法
        System.out.println("提交事务...");
        return returnValue;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 三、应用场景

# 1、Spring AOP底层实现

在Spring AOP中,有一个类DefaultAopProxyFactory,它下面有一个方法createAopProxy(),里面会判断目标类是否可以表示为接口类型,如果是的话就使用JDK动态代理JdkDynamicAopProxy,否则就使用Cglib动态代理ObjenesisCglibAopProxy

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 四、思维导图

#设计模式
设计模式之享元模式
设计模式之责任链模式

← 设计模式之享元模式 设计模式之责任链模式→

最近更新
01
otter二次开发-支持按目标端主键索引Load数据
08-03
02
mvnw简介
06-21
03
gor流量复制工具
06-03
更多文章>
Theme by Vdoing | Copyright © 2022-2024 元月 | 粤ICP备2022071877号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式