JDK动态代理:
概述:
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。详细介绍请参考:java设计模式之代理模式。为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。
- 在java的动态代理机制中一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class).
文章参考引用自:https://blog.csdn.net/xiaokang123456kao/article/details/77679848
-
- 声明接口
package com.feifan.jdk;
import java.util.List;
/**
* 需要动态代理的接口
* @author Donald
* 2018-11-27 22:23:34
*/
public interface ProxyInterface {
public String sayHello();
public List<String> listShow();
public void sayNothing(String ... strings);
public String arrayReturn(Object[] args);
}
-
- 声明实现类
package com.feifan.jdk;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 具体的实现类
* @author Donald
* 2018-11-27 22:27:03
*/
public class ProxyInterfaceImpl implements ProxyInterface {
@Override
public String sayHello() {
return "sayHello ====NoParmater";
}
@Override
public List<String> listShow() {
List<String> list= new ArrayList<>();
list.add("wang");
list.add("ming");
list.add("huhu");
return list;
}
@Override
public String arrayReturn(Object[] args) {
String string=Arrays.toString(args);
return string;
}
@Override
public void sayNothing(String... strings) {
System.out.println(Arrays.toString(strings));
}
}
-
- 声明InvokeHandler 实现类
package com.feifan.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
*每次生成动态代理类对象都需要指定一个实现InvocationHandler接口的调用处理器对象
* @author Donald
* 2018-11-27 22:37:43
*/
public class InvokHandler implements InvocationHandler{
//这个就是我们需要代理的真实对象。
private Object subject;
public InvokHandler(Object subject) {
this.subject = subject;
}
/**
* 一个动态代理类都必须要实现InvocationHandler这个接口,
* 并且每个代理类的实例都关联了一个handler,当我们通过代理对象调用一个方法的时候,
* 这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
* 我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
* @param proxy 指代JDK动态生成的最终代理对象
* @param method 指代的是我们所要调用真实对象的某个方法的Method对象
* @param args 指代的是调用真实对象某个方法时接受的参数
* @return method对应的方法 的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=null;
try {
System.out.println("前置通知:当前调用的方法是:"+method.getName());
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象
//关联的handler对象 的invoke方法进行调用。
result=method.invoke(subject, args);//指定被代理的对象和参数
System.out.println("后置通知:程序正常执行之后result...."+result);
} catch (Exception e) {
System.out.println("方法执行异常通知Exception:"+e.getMessage());
}
System.out.println("方法执行了通知");
return result;
}
}
- 测试
- //loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来生成代理对象进行加载
//interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
//h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上,间接通过invoke来执行
package com.feifan.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
public class TestJDKProxy {
@Test
public void JDKTest() {
//1.被代理对象
ProxyInterface proxyInterface= new ProxyInterfaceImpl();
//2.InvocationHandler 的实现类
InvokHandler invokHandler=new InvokHandler(proxyInterface);
//3.调用Proxy的静态方法
/**
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
* ClassLoader loader,类加载器
* Class<?>[] interfaces,目标对象实现的接口
* InvocationHandler h:InvocationHandler 的实现类
*/
ProxyInterface newProxy = (ProxyInterface)Proxy.newProxyInstance(proxyInterface.getClass().getClassLoader()
, proxyInterface.getClass().getInterfaces()
, invokHandler);
//此处会调用newProxy的toString 方法
System.out.println("newProxy动态代理对象内存地址:"+newProxy+"\t>>newProxyname:"+newProxy.getClass().getSimpleName());
List<String> listShow = newProxy.listShow();
System.out.println("listShow"+listShow);
System.out.println("-------------------");
newProxy.sayNothing("sss","sds","ssK");
System.out.println("-------------------");
Object [] kObjects={"ddd","dd","ff"};
String arrayReturn = newProxy.arrayReturn(kObjects);
System.out.println(arrayReturn);
}
}
- 结果:
JDK内置的Proxy动态代理可以在运行时动态生成字节码,而没必要针对每个类编写代理类。中间主要使用到了一个接口InvocationHandler与Proxy.newProxyInstance静态方法,参数说明如下:
使用内置的Proxy实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。
CGLIB 代理实现:
CGLIB是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理.
CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口,通俗说cglib可以在运行时动态生成字节码。
- 实体类
package com.feifan.cglib;
public class CglibEntity {
public void cg() {
System.out.println("CGLIB 代理类 无参");
}
public void cg1(String name)
{
System.out.println("CGLIB 代理测试:name"+name);
}
public void cg2() {
int k=1/0;
}
}
- 动态代理类
package com.feifan.cglib;
import static org.hamcrest.CoreMatchers.nullValue;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 动态代理类、实现一个方法拦截器接口
* @author Donald
* 2018-11-28 20:57:11
*/
public class CglibDynamic implements MethodInterceptor{
//被代理的对象
Object targetObject;
//动态生成一个新的类,使用父类的无参构造方法创建一个指定了特定回调的代理实例。
public Object getCglibObject(Object object)
{
targetObject=object;
//增强器,动态代码生成器
Enhancer enhancer= new Enhancer();
//回调方法
enhancer.setCallback(this);
//设置生成类的父类类型
enhancer.setSuperclass(targetObject.getClass());
//动态生成字节码并返回代理对象
Object object2 = enhancer.create();
//System.out.println(object2+">>>>");
return object2;
}
//拦截方法
/**
* Object为由CGLib动态生成的代理类实例,
* Method为上文中实体类所调用的被代理的方法引用,
* Object[]为参数值列表,
* MethodProxy为生成的代理类对方法的代理引用。
* 返回:从代理实例的方法调用返回的值。
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result =null;
// 被织入的横切内容,开始时间Before
System.out.println("cglib方法执行之前");
//调用方法
try {
result = proxy.invoke(targetObject, args);
System.out.println("CGLIB目标方法正常执行了"+proxy.getSignature().getName());
} catch (Exception e) {
e.printStackTrace();
System.out.println("cglib方法执行异常");
}
System.out.println("cglib目标方法执行了");
return result;
}
}
- 测试方法
package com.feifan.cglib;
import org.junit.Test;
public class CglibTest {
@Test
public void cglibTest() {
CglibEntity cglibEntity= new CglibEntity();
CglibDynamic cglibDynamic=new CglibDynamic();
System.out.println("------");
CglibEntity cglibTarget = (CglibEntity)cglibDynamic.getCglibObject(cglibEntity);
System.out.println(cglibTarget+"------");
cglibTarget.cg1("HIJI");
cglibTarget.cg2();
}
}
- 测试结果
代码参考:
链接:https://pan.baidu.com/s/10wC0L53eVsc6EeIs2JiQDA
提取码:lwnd