在开发中会有这种情况 , 你有a类 , 本来是调用c 类中的方法 , 完成某个功能 , 但是c不让a调用 ,
a ---- 不能调用c的方法
在 a和c中间直接创建一个 b 代理 , c 让 b 访问 , a – 访问 b – b 访问 c
代理模式 :
代理模式是指 , 为其他对象提供一种代理 以控制对这个对象的访问 , 在某些情况下 , 一个对象不适合或者不能直接引用另一个对象 , 而代理对象可以在客户类和目标对象直接起到中介的作用 ,
换句话说 , 使用代理对象 , 是为了在不修改目标对象的基础上 , 增强主业务的逻辑 ,
使用代理模式的作用 :
- 功能增强 : 在你原有的基础上 ,增加了额外的功能 , 新增加的功能 , 叫做功能增强
- 控制访问 : 代理类不让你访问目标 , 例如 , 实体类中 , 不让直接访问实体类的内容 ,但是添加了get 和set方法 , 用来对内容进行修改
静态代理:
- 代理类是自己手工实现的 , 自己创建的一个java类 , 代表代理类
- 同时你所要代理的目标是确定的
特点 : 实现简单 , 容易理解
实现步骤 :
- 创建一个接口 , 定一个方法 , 表示你的厂家和商家要做的事情
- 创建厂家类 , 实现一步骤的接口
- 创建商家 , 就是代理 , 也要实现1步骤中的接口
- 创建客户端类 , 调用商家的方法买
缺点:
- 当目标类增加了 , 代理类也需要成倍的增加 , 代理类数量过多
- 当你的接口中功能增加了 , 会影响众多的实现类 , 厂家类 , 代理类都需要修改 , 影响比较大
动态代理:
在静态代理中目标类很多的时候 , 可以使用动态代理 , 避免静态代理的缺点
优点 :
动态代理中目标类即使很多 ,
- 代理类数量可以很少
- 当你修改了接口中的方法时 , 不会影响代理类
动态代理简介 :
基于反射机制 :
使用jdk的反射机制 , 创建对象的能力 , 创建的是代理类的对象 , 而不用你写java对象
换句话说 ,动态代理是一种创建java对象的能力 , 让你不用创建实现类 , 就能创建代理对象
在java中 , 想要创建对象 ,
- 创建类文件 , java文件编译为class
- 使用构造方法 , 创建类的对象
动态代理的实现分类 :
-
动态代理分类:
动态代理是指 : 程序在整个运行过程中根本就不存在目标类的代理类 , 目标对象的代理对象只是由代理生成工具(不是真实定义的类) 在程序运行时由JVM根据反射等机制 , 动态生成的 , 代理对象与目标对象的代理关系在程序运行的时候才确立
JDK动态代理 :
动态代理的实现方式常用的有两种 , 使用JDK的Proxy , 和通过CGLIB生成代理
JDK的动态代理要求目标对象必须有实现接口, 这是java设计上的要求
从jdk1.3以来 , java语言通过java.lang.reflect 包提供三个类支持代理模式 Proxy , Method ,和InovcationHandler
CGLID动态代理 :
CGLIB (Code Generation Library)是一个开源项目 , 是一个强大的 , 高性能 ,高质量的Code生成类库
它可以在运行期间扩展java类与实现java接口 , 它广泛的呗许多AOP的框架使用 , 例如Spring AOP
对于无接口的类, 要为其创建动态代理 , 就要使用CGLIB来实现
CGLIB代理的方式是 : 生成目标类的子类 , 而子类是增强过的 , 这个子类对象就是代理对象 , 所以使用CGLIB生成动态代理的要求就是 目标类能够被继承 , 即不能是final的类
CGLIB经常被应用在框架中 , Spring , Hibernate等 cglib代理的效率高于jdk
项目中使用动态代理的地方不多 , 一般都是使用框架提供的功能
JDK动态代理 主要类简介:
反射包中 java.lang.reflect , 里面有三个类 , :
(1) InvocationHandler 接口 ( 中文名称叫做 : 调用处理器 )
-
这是一个接口 , 在这个接口中只有一个方法 , invoke ()
-
invoke():表示代理对象要执行的功能代码 , 你的代理类要完成的功能就写在invoke()方法当中
- 代理类要完成的功能 :
- 调用目标方法: 执行目标方法的功能
- 功能增加 : 在目标方法调用的时候 , 增加功能
- 代理类要完成的功能 :
-
public Object invoke(Object proxy, Method method, Object[] args) Object proxy : JDK创建的代理对象 , 无需赋值 Method method : 目标类中的方法 ,JDK提供的method对象 , Object[] args : 目标类中方法的参数
怎么用 : InvocationHandler 接口 :表示你的代理要干什么
- 我们要创建一个类 , 实现这个接口
- 重写invoke()方法 , 把原来静态代理中代理类要完成的功能 , 写在这里
(2) Method ()
这是一个类 : 确切的说 , 他就是你的目标类中的方法 ,
作用 : 通过Method可以执行某个目标类的方法 ,
- Method.invoke();
- 这个invoke和上边的invoke是不一样的 , 这个只是 Method类中的一个方法
method.invoke(目标对象 , 方法的参数);
通过这个方法 , 可以直接执行这个对象中的方法 , 而不需要知道方法的名称 ,
(3) Proxy : 核心的对象 , 创建代理对象 ,
方法 : newProxyInstance()
作用是 : 创建代理对象
public static Object newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), new InvocationHandler())
/*
参数 :
ClassLoader loader : 类加载器 , 负责向内存中加载对象的 , 使用反射获取对象的ClassLoader
使用的是目标对象的类加载器
Class<?>[] interfaces : 接口 , 目标对象实现的接口 , 也是反射获取的
InvocationHandler h : 我们自己写的代理类要完成的功能
返回值 : 就是代理对象
*/
动态代理实现步骤 JDK :
动态代理的实现步骤 :JDK
1.创建目标类 , SomeServiceImpl 目标类 , 给它的方法进行增强
2.创建InvocationHandler接口的实现类 , 在这个类实现给目标方法增加功能 (或者直接创建内部类也行)
3.使用JDK中类 , Proxy创建代理对象 , 实现创建对象的能力 , 使用代理对象调用目标方法
//使用jdk的Proxy创建代理对象
//创建目标对象
SomeService target = new SomeServiceImpl();
//使用Proxy创建代理
SomeService proxy = (SomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InvocationHandler() {
@Override
//通过代理对象执行方法时 , 会调用执行这个invoke()
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行了内部类的方法");
Object res = null;
myUtil.vlog();//增强功能
//执行目标类的方法 , 通过Method类实现 , method就是目标方法
res = method.invoke(target, args);
//执行的是SomeServiceImpl中的方法 , 这里的target就是SomeServiceImpl目标类
//SomeService target = new SomeServiceImpl();
//arg就是传递过来的值 , 是在下边调用的时候 , 传递的
myUtil.aVoid();//增强功能
return res;
}
});
//proxy就是创建的代理对象 , 这里调用的是什么方法 ,
// method.invoke(target, args); 执行的就是什么方法
proxy.doOther();
//通过代理执行方法 , 会调用上边的中的invoke()方法(继承的那个方法)