java-动态代理
代理模式
代理模式是Java中常用的设计模式,主要由公共接口、被代理类和代理类等三部分组成,代理类持有被代理类的实类,代为执行具体的类方法。其中代理类与被代理类有同样的接口。
代理类与被代理类之间通常会存在关联关系,一个代理类的对象与一个被代理类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用被代理类对象的方法来提供特定的服务。
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起中介的作用。
代理模式UML
- Subject:抽象主题角色,抽象主题类可以是抽象类,也可以是接口,是一个最普通的业务类型定义,无特殊要求。
- RealSubject:具体主题角色,也叫被委托对象,被代理角色。是业务逻辑的具体执行者
- Proxy:代理主题角色,也叫委托类、代理类。它把所有抽象主题类定义的方法给具体主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后工作。
代理模式
根据加载被代理类的时机不同,将代理分为静态代理和动态代理。
静态代理,程序运行之前就已经存在的编译好的代理类
动态代理,程序运行时动态生成,根据java的反射机制动态生成
静态代理
静态代理:在代码编译时就确定了具体的被代理类。由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
代码案例
//IMacSeller.java
public interface IMacSeller{
void buy()
}
//USAMacSeller.java
public class USAMacSeller implements IMacSeller{
@Override
public void buy(){
System.out.println("buy a macbook from USA")
}
}
//HongkongMacSeller.java
public class HongkongMacSeller implements IMacSeller{
IMacSeller seller =new USAMacSeller();
@Override
public void buy(){
seller.buy();
System.out.println("buy a macbook from Hongkong");
}
}
//Client.java
public class Client{
public static void main(String[] args){
System.out.println("Proxy main");
IMacSeller seller = new HongkongMacSeller();
seller.buy();
}
}
JAVA动态代理
什么是动态代理
使用jdk的反射机制,创建对象的能力,创建的是代理类的的对象.而不用我们创建类文件,不用写java文件。什么叫动态?在程序执行时,调用jdk提供的方法才能创建代理类的对象
动态代理介绍
- 动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。
- 动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
- 动态代理的实现方式常用的有两种:使用JDK代理,与通过CGLlB动态代理。
动态代理的实现(2种方式)
- jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy
- cglib动态代理(了解): cglib是第三方的工具库,创建代理对象
- cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法,实现功能的修改。
- 因为cglib是继承,重写方法,所以要求目标类不能是final的,方法也不能是final的。cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,比如mybatis,spring框架中都有使用。
JDK动态代理主要方法说明
jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandler
、Method
、Proxy
1. 反射 (理解反射的method.invoke方法)
Method类,表示方法。类中的方法,通过反射 Method可以执行某个方法
method.invoke() 反射调用方法
2. jdk动态代理的实现
创建动态代理类会使用到java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口。
反射包 java.lang.reflect ,里面有3个类:InvocationHandler,Method,Proxy
java.lang.reflect.Proxy
java.lang.reflect.Proxy
主要用于生成动态代理类Class
、创建代理类实例,该类实现了java.io.Serializable
接口。
创建代理类:Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
java.lang.reflect.Proxy
类主要方法如下:
package java.lang.reflect;
import java.lang.reflect.InvocationHandler;
/**
* Creator: yz
* Date: 2020/1/15
*/
public class Proxy implements java.io.Serializable {
// 省去成员变量和部分类方法...
/**
* 获取动态代理处理类对象
*
* @param proxy 返回调用处理程序的代理实例
* @return 代理实例的调用处理程序
* @throws IllegalArgumentException 如果参数不是一个代理实例
*/
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException {
...
}
/**
* 创建动态代理类实例
*
* @param loader 指定动态代理类的类加载器
* @param interfaces 指定动态代理类的类需要实现的接口数组
* @param h 动态代理处理类
* @return 返回动态代理生成的代理类实例
* @throws IllegalArgumentException 不正确的参数异常
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException {
...
}
/**
* 创建动态代理类
*
* @param loader 定义代理类的类加载器
* @param interfaces 代理类要实现的接口列表
* @return 用指定的类加载器定义的代理类,它可以实现指定的接口
*/
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) {
...
}
/**
* 检测某个类是否是动态代理类
*
* @param cl 要测试的类
* @return 如该类为代理类,则为 true,否则为 false
*/
public static boolean isProxyClass(Class<?> cl) {
return java.lang.reflect.Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
}
/**
* 向指定的类加载器中定义一个类对象
*
* @param loader 类加载器
* @param name 类名
* @param b 类字节码
* @param off 截取开始位置
* @param len 截取长度
* @return JVM创建的类Class对象
*/
private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);
}
java中要创建一个代理对象,必须调用Proxy
类的静态方法newProInstance
,该方法原型如下:
Object Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler) throws IllegalArgumentException
//loader,表示类加载器,对于不同来源(系统库或网络等)的类需要不同的类加载器来加载,这是java安全模型的一部分。
//interfaces,它就是被代理类对象的共有的接口
//handler,表示调用处理器,它必须是实现了InvocationHandler接口的对象,其作用是定义代理对象中需要执行的具体操作
java.lang.reflect.InvocationHandler
InvocationHandler 接口只有一个方法invoke
,定义了代理对象在执行真实对象的方法时所希望执行的动作
invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在invoke中
代理类完成的功能:
1、调用目标方法,执行目标方法的功能
2、功能增强,在目标方法调用时,增加功能
方法原型:
Object invoke(Object proxy,Method method,Object[] args) throws Throwable
// proxy,jdk创建的代理对象,无需赋值
// method,目标类中的方法,jdk提供的method对象
// args,目标类中方法的参数,jdk提供
InvocationHandler接口:表示你的代理要干什么
怎么用:
1.创建类实现接口InvocationHandler
2.重写invoke()方法,把原来静态代理中代理类要完成的功能写到这里
3. JDK动态代理案例
定义接口ImiSeller
package com.tyut.dynamic;
public interface ImiSeller {
void buy();
}
实现接口的目标实现类Mistore
package com.tyut.dynamic;
public class Mistore implements ImiSeller {
@Override
public void buy() {
System.out.println("通过小米商店买了一部小米手机");
}
}
定义代理类实现的具体增强类MyHandler
,重写invoke
方法,代理类具体执行的方法
package com.tyut.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyHandler implements InvocationHandler {
Object proxyTarget;
public MyHandler(Object proxyTarget) {
this.proxyTarget = proxyTarget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(proxyTarget,args); //个人理解,通过反射调用目标类方法,这里的invoke是反射,上面的invoke是invocationHandler接口的方法
System.out.println("增强代理方式实现");
return null;
}
}
创建代理对象并执行代理方法
package com.tyut.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class MyApp {
public static void main(String[] args) {
// 目标类
ImiSeller sell = new Mistore();
//实现InvocationHandle接口中的invoke方法,并将被代理的实例对象传入,相当于之前的代理类,谁使用它,它就返回谁的对象,
InvocationHandler myhandler = new MyHandler(sell);
// 动态生成代理类对象
// 指定动态代理类的类加载器 sell.getClass().getClassLoader()
// 定义动态代理类 实现的接口 sell.getClass().getInterfaces()
// 动态代理处理类
ImiSeller proxy = (ImiSeller) Proxy.newProxyInstance(sell.getClass().getClassLoader(), sell.getClass().getInterfaces(),myhandler);
//使用生成的代理类,调用invoke中定义的方法
proxy.buy();
}
}
通过动态代理就可以动态生成代理类,实现接口InvocationHandler的类(这个实现InvocationHandler的类相当于定义好被代理类的相关操作),最后然后通过Proxy类的newProxyInstance方法来生成动态代理类!