写在前面的话
复习、总结23种设计模式
上一篇
代理模式
记重点
定义
为其他对象提供一种代理以控制对这个对象的访问
代理模式的通用类图
Subject抽象主题角色
抽象主题类尅是抽象类也可以是接口,是一个最普通的业务类型定义,没有特殊要求
package com.design.pattern.proxy.test02;
// Subject抽象主题角色
public interface Subject {
void request();
}
RealSubject真实主题角色
也叫做委托角色,被代理角色,它才是冤大头,是业务逻辑的具体执行者
package com.design.pattern.proxy.test02;
// 真实主题角色
public class RealSubject implements Subject{
@Override
public void request() {
System.out.println("do sth.");
}
}
Proxy代理主题角色
也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后工作
package com.design.pattern.proxy.test02;
// Proxy代理主题角色
public class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
before();
subject.request();
after();
}
private void before() {
System.out.println("预处理...");
}
private void after() {
System.out.println("善后...");
}
}
测试类
package com.design.pattern.proxy.test02;
// 测试类
public class Client {
public static void main(String[] args) {
// 真实对象
Subject realSubject = new RealSubject();
// 代理对象
Subject proxy = new Proxy(realSubject);
proxy.request();
}
}
静态代理
定义
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。
以打游戏+找代练为例实战
定义打游戏的接口
package com.design.pattern.proxy.test01;
// 打游戏
public interface IGamePlayer {
// 游戏登录
void login(String username, String password);
// 打怪
void killBoss();
// 升级
void upgrade();
}
具体的游戏玩家
package com.design.pattern.proxy.test01;
// 具体的游戏玩家
public class GamePlayer implements IGamePlayer {
private String nickname;
public GamePlayer(String nickname) {
this.nickname = nickname;
}
@Override
public void login(String username, String password) {
System.out.println("登录名为" + username + "的用户" + nickname + "登录成功");
}
@Override
public void killBoss() {
System.out.println(nickname + "正在打boss...");
}
@Override
public void upgrade() {
System.out.println(nickname + "又升了一级");
}
}
不找游戏代练,自己打游戏
package com.design.pattern.proxy.test01;
// 自己打游戏
public class Client {
public static void main(String[] args) {
IGamePlayer gamePlayer = new GamePlayer("豆豆");
System.out.println("开始时间:" + System.currentTimeMillis());
gamePlayer.login("username1", "password1");
gamePlayer.killBoss();
gamePlayer.upgrade();
System.out.println("结束时间:" + System.currentTimeMillis());
}
}
找个游戏代练
package com.design.pattern.proxy.test03;
import com.design.pattern.proxy.test01.IGamePlayer;
// 游戏代练
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer iGamePlayer;
public GamePlayerProxy(IGamePlayer iGamePlayer) {
this.iGamePlayer = iGamePlayer;
}
@Override
public void login(String username, String password) {
iGamePlayer.login(username, password);
}
@Override
public void killBoss() {
iGamePlayer.killBoss();
}
@Override
public void upgrade() {
iGamePlayer.upgrade();
}
}
让游戏代练帮你打游戏
package com.design.pattern.proxy.test03;
import com.design.pattern.proxy.test01.GamePlayer;
import com.design.pattern.proxy.test01.IGamePlayer;
// 让游戏代练帮你打游戏
public class Client {
public static void main(String[] args) {
IGamePlayer gamePlayer = new GamePlayer("豆豆");
// 定义一个游戏代练
IGamePlayer proxy = new GamePlayerProxy(gamePlayer);
System.out.println("开始时间:" + System.currentTimeMillis());
proxy.login("username1", "password1");
proxy.killBoss();
proxy.upgrade();
System.out.println("结束时间:" + System.currentTimeMillis());
}
}
总结:
- 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现接口或继承相同的父类
缺点:
- 因为代理对象需要和被代理对象实现相同的接口或父类,所以会有太多的代理类
- 一旦接口中增加了方法后,被代理对象和代理对象都需要维护(非常麻烦,不方便)
jdk动态代理
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
package com.design.pattern.proxy.jdk04.test05;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class GamePlayerIH implements InvocationHandler {
// 被代理实例,invoke方法里面method需要使用这个被代理对象
private Object target;
public GamePlayerIH(Object target) {
this.target = target;
}
/**
* 核心方法,它完成对真实方法的调用
*
* @param proxy 代表动态生成的 动态代理 对象实例
* @param method 代表被调用委托类的接口方法,和生成的代理类实例调用的接口方法是一致的,它对应的Method 实例
* @param args 代表调用接口方法对应的Object参数数组,如果接口是无参,则为null; 对于原始数据类型返回的他的包装类型。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("被动态代理类回调执行, 代理类 proxyClass =" + proxy.getClass());
System.out.println("方法名: " + method.getName() + "方法. 方法返回类型:" + method.getReturnType());
System.out.println("接口方法入参数组: " + (args == null ? "null" : Arrays.toString(args)));
System.out.println("前置通知...");
// 调用被代理对象的真实方法
Object result = method.invoke(target, args);
System.out.println("后置通知...");
return result;
}
}
package com.design.pattern.proxy.jdk04.test05;
import com.design.pattern.proxy.test01.GamePlayer;
import com.design.pattern.proxy.test01.IGamePlayer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Properties;
public class Client {
public static void main(String[] args) throws Exception {
// 打开保存JDK动态代理生成的类文件
saveGeneratedJdkProxyFiles();
// 定义一个游戏玩家
GamePlayer gamePlayer = new GamePlayer("doudou");
// 定义一个handler
InvocationHandler handler = new GamePlayerIH(gamePlayer);
// 动态生产一个代理者
IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(
gamePlayer.getClass().getClassLoader(),
new Class<?>[]{IGamePlayer.class},
handler);
System.out.println("开始时间:" + System.currentTimeMillis());
proxy.login("username1", "password1");
proxy.killBoss();
proxy.upgrade();
System.out.println("结束时间:" + System.currentTimeMillis());
}
/**
* 设置保存Java动态代理生成的类文件到我们的module下
*/
public static void saveGeneratedJdkProxyFiles() throws Exception {
Field field = System.class.getDeclaredField("props");
field.setAccessible(true);
Properties props = (Properties) field.get(null);
props.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
}
}
程序运行时动态生成的代理类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.sun.proxy;
import com.design.pattern.proxy.test01.IGamePlayer;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements IGamePlayer {
private static Method m1;
private static Method m2;
private static Method m5;
private static Method m4;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void upgrade() throws {
try {
super.h.invoke(this, m5, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void killBoss() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void login(String var1, String var2) throws {
try {
super.h.invoke(this, m3, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m5 = Class.forName("com.design.pattern.proxy.test01.IGamePlayer").getMethod("upgrade");
m4 = Class.forName("com.design.pattern.proxy.test01.IGamePlayer").getMethod("killBoss");
m3 = Class.forName("com.design.pattern.proxy.test01.IGamePlayer").getMethod("login", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
第二种创建jdk动态代理的方法
创建Person接口,用于定义委托类和代理类之间的约束行为
package com.design.pattern.proxy.jdk04.test06;
/**
* 创建Person 接口 用于定义 委托类和代理类之间的约束行为
*/
public interface Person {
/**
* @param name 人名
* @param dst 工作目的地
*/
void goWorking(String name, String dst);
/**
* 获取名称
*
* @return
*/
String getName();
/**
* 设置名称
*
* @param name
*/
void setName(String name);
}
动态代理委托类实现, 实现接口Person。被动态生成的代理类代理
package com.design.pattern.proxy.jdk04.test06;
/**
* 动态代理委托类实现, 实现接口 Person。 被动态生成的代理类代理
*/
public class SoftwareEngineer implements Person {
private String name;
public SoftwareEngineer() {
}
public SoftwareEngineer(String name) {
this.name = name;
}
@Override
public void goWorking(String name, String dst) {
System.out.println("name =" + name + ",去" + dst + "工作");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
增强类
package com.design.pattern.proxy.jdk04.test06;
/**
* 监控类
*/
public class MonitorUtil {
private static ThreadLocal<Long> tl = new ThreadLocal<>();
public static void start() {
tl.set(System.currentTimeMillis());
}
/**
* 结束时打印耗时
*
* @param methodName 方法名
*/
public static void finish(String methodName) {
long finishTime = System.currentTimeMillis();
System.out.println(methodName + "方法执行耗时" + (finishTime - tl.get()) + "ms");
}
}
PersonInvocationHandler类实现InvocationHandler接口,这个类中持有一个被代理对象(委托类)的实例target。该类别JDK Proxy类回调InvocationHandler 接口中有一个invoke方法,当一个代理实例的方法被调用时,代理方法将被编码并分发到 InvocationHandler接口的invoke方法执行。
package com.design.pattern.proxy.jdk04.test06;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* PersonInvocationHandler 类 实现InvocationHandler接口,这个类中持有一个被代理对象(委托类)的实例target。该类别JDK Proxy类回调
* InvocationHandler 接口中有一个invoke方法,当一个代理实例的方法被调用时,代理方法将被编码并分发到 InvocationHandler接口的invoke方法执行。
*/
public class PersonInvocationHandler<T> implements InvocationHandler {
/**
* 被代理对象引用,invoke 方法里面method 需要使用这个 被代理对象
*/
T target;
public PersonInvocationHandler(T target) {
this.target = target;
}
/**
* @param proxy 代表动态生成的 动态代理 对象实例
* @param method 代表被调用委托类的接口方法,和生成的代理类实例调用的接口方法是一致的,它对应的Method 实例
* @param args 代表调用接口方法对应的Object参数数组,如果接口是无参,则为null; 对于原始数据类型返回的他的包装类型。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 在转调具体目标对象之前,可以执行一些功能处理
*/
System.out.println("被动态代理类回调执行, 代理类 proxyClass =" + proxy.getClass() + " 方法名: " + method.getName() + "方法. 方法返回类型:" + method.getReturnType() + " 接口方法入参数组: " + (args == null ? "null" : Arrays.toString(args))); /**
* 代理过程中插入监测方法,计算该方法耗时
*/
MonitorUtil.start();
Thread.sleep(1);
/** 调用被代理对象的真实方法,*/
Object result = method.invoke(target, args);
MonitorUtil.finish(method.getName());
return result;
}
}
动态代理对象步骤
- 创建一个与代理对象相关联的 InvocationHandler,以及真实的委托类实例
- Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass,该类继承Proxy类,实现 Person.java接口;JDK动态代理的特点是代理类必须继承Proxy类
- 通过代理类 proxyClass 获得他的带InvocationHandler 接口的构造函数 ProxyConstructor
- 通过 构造函数实例 ProxyConstructor 实例化一个代理对象,并将 InvocationHandler 接口实例传递给代理类。
package com.design.pattern.proxy.jdk04.test06;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
public class Client {
public static void main(String[] args) {
/**
* 动态代理对象步骤
* 1、 创建一个与代理对象相关联的 InvocationHandler,以及真实的委托类实例
* 2、Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass,该类继承Proxy类,实现 Person.java接口;JDK动态代理的特点是代理类必须继承Proxy类
* 3、通过代理类 proxyClass 获得他的带InvocationHandler 接口的构造函数 ProxyConstructor
* 4、通过 构造函数实例 ProxyConstructor 实例化一个代理对象,并将 InvocationHandler 接口实例传递给代理类。
*/
try {
run();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void run() throws Exception {
// 这是我们真实对象
Person persontwo = new SoftwareEngineer("豆豆");
// 1、创建 InvocationHandler 实例并设置代理的目标类对象
InvocationHandler handler = new PersonInvocationHandler<>(persontwo);
// 2、 创建代理类,是一个字节码文件, 把 proxyClass 保存起来就能看到 他继承Proxy 类,实现Person接口
Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), Person.class);
// 代理类信息
System.out.println("package = " + proxyClass.getPackage()
+ " SimpleName = " + proxyClass.getSimpleName()
+ " name =" + proxyClass.getName()
+ " CanonicalName = " + proxyClass.getCanonicalName()
+ " 实现的接口 Interfaces = " + Arrays.toString(proxyClass.getInterfaces())
+ " superClass = " + proxyClass.getSuperclass()
+ " methods =" + Arrays.toString(proxyClass.getMethods()));
// 3、通过 proxyClass 获得 一个带有InvocationHandler参数的构造器constructor
Constructor<?> ProxyConstructor = proxyClass.getConstructor(InvocationHandler.class);
// 4、通过构造器创建一个 动态代理类 实例
Person stuProxy = (Person) ProxyConstructor.newInstance(handler);
// 检测生成的类是否是代理类
System.out.println("stuProxy isProxy " + Proxy.isProxyClass(stuProxy.getClass()));
// 获取 代理类关联的 InvocationHandler 是哪个
InvocationHandler handlerObject = Proxy.getInvocationHandler(stuProxy);
System.out.println(handlerObject.getClass().getName());
stuProxy.goWorking(stuProxy.getName(), "广州");
// 保存代理类
String pathdir = "/Users/benjamin/IntelliJIdeaProjects/springboot-mydemo/demo/jdkdynamicclasses";
saveClass("$PersonProxy0", proxyClass.getInterfaces(), pathdir);
}
/**
* 生成代理类 class 并保持到文件中
*
* @param className 生成的代理类名称
* @param interfaces 代理类需要实现的接口
* @param pathdir 代理类保存的目录路径,以目录分隔符结尾
*/
public static void saveClass(String className, Class<?>[] interfaces, String pathdir) {
/**
* 第一个参数是 代理类 名 。
* 第二个参数是 代理类需要实现的接口
*/
byte[] classFile = ProxyGenerator.generateProxyClass(className, interfaces);
/**
* 如果目录不存在就新建所有子目录
*/
Path path1 = Paths.get(pathdir);
if (!path1.toFile().exists()) {
path1.toFile().mkdirs();
}
String path = pathdir + className + ".class";
try (FileOutputStream fos = new FileOutputStream(path)) {
fos.write(classFile);
fos.flush();
System.out.println("代理类class文件写入成功");
} catch (Exception e) {
System.out.println("写文件错误");
}
}
}
cglib动态代理
静态代理和jdk动态代理都要求目标对象实现接口,
cglib动态代理,使用以目标对象子类的方式实现代理,(当目标对象是一个单独的对象,没有实现任何接口时使用).
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,为其提供方法的interception(拦截),例如大家所熟知的Spring AOP。
Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类。
Cglib子类代理需要注意的是:
- 需要引入cglib的jar包
- 代理的类不能是final,否则报错
- 目标对象的方法如果有final/static,那么不会被拦截,即不会执行目标对象额外的业务方法。
实现步骤:
步骤1:引入jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
DEMO-1
创建被代理的类
package com.design.pattern.proxy.cglib05.test09;
public class SqlService {
public void executeSql1() throws InterruptedException {
System.out.println("Sql 开始执行.....");
Thread.sleep(1000);
System.out.println("Sql 执行结束.....");
}
public void executeSql2() throws InterruptedException {
System.out.println("Sql2 开始执行.....");
Thread.sleep(1000);
System.out.println("Sql2 执行结束.....");
}
}
自定义MethodInterceptor
package com.design.pattern.proxy.cglib05.test09;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class SqlFacadeCglib implements MethodInterceptor {
/**
* 被代理的对象
*/
private Object target;
public SqlFacadeCglib(Object target) {
this.target = target;
}
/**
* 实现回调方法
*
* @param obj 代理的对象
* @param method 被代理对象的方法
* @param args 参数集合
* @param proxy 生成的代理类的方法
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 开始执行时间
Long startTime = System.currentTimeMillis();
// //调用业务类(父类中)的方法
Object result = proxy.invokeSuper(obj, args);
// 执行结束
Long endTime = System.currentTimeMillis();
System.out.println(target.getClass().getName()
+ "执行executeSql耗时" + (endTime - startTime) + "ms");
return result;
}
}
测试
package com.design.pattern.proxy.cglib05.test09;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
public class CglibTest {
public static void main(String[] args) throws InterruptedException {
// 将class 文件保存
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\WorkspaceIdea\\01src\\java-design-pattern\\ProxyPattern08\\src\\main\\java");
SqlService sqlService = new SqlService();
SqlFacadeCglib sqlFacadeCglib = new SqlFacadeCglib(sqlService);
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(sqlService.getClass());
// 可以为不同的method使用不同的callback
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
// 使用第一个callback
return 0;
}
});
enhancer.setCallbackTypes(new Class<?>[]{MethodInterceptor.class});
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(sqlFacadeCglib);
// 创建动态代理类对象并返回
SqlService sqlServiceProxy = (SqlService) enhancer.create();
// 调用
sqlServiceProxy.executeSql1();
System.out.println("--------------------------");
System.out.println(sqlServiceProxy.getClass().getName());
}
}
DEMO-2
package com.design.pattern.proxy.cglib05.test10;
import java.util.Arrays;
import java.util.List;
public class DBQuery {
public DBQuery() {
}
public DBQuery(Integer i) {
System.out.println("Here's in DBQuery Constructor");
}
public String getElement(String id) {
return id + "_CGLib";
}
public List<String> getAllElements() {
return Arrays.asList("Hello_CGLib1", "Hello_CGLib2");
}
public String methodForNoop() {
return "Hello_Noop";
}
public String methodForFixedValue(String param) {
return "Hello_" + param;
}
public final String sayHello() {
return "Hello Everyone!";
}
}
package com.design.pattern.proxy.cglib05.test10;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DBQueryProxy implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Here in interceptor !");
return methodProxy.invokeSuper(o, objects);
}
}
package com.design.pattern.proxy.cglib05.test10;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DBQueryProxy2 implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Here in interceptor 2!");
return methodProxy.invokeSuper(o, objects);
}
}
package com.design.pattern.proxy.cglib05.test10;
import net.sf.cglib.proxy.FixedValue;
public class DBQueryProxyFixedValue implements FixedValue {
public Object loadObject() throws Exception {
System.out.println("Here in DBQueryProxyFixedValue ! ");
return "Fixed Value";
}
}
package com.design.pattern.proxy.cglib05.test10;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
import java.lang.reflect.Method;
public class TestCGLibProxy {
public static void main(String[] args) {
DBQueryProxy dbQueryProxy = new DBQueryProxy();
DBQueryProxy2 dbQueryProxy2 = new DBQueryProxy2();
Callback noopCb = NoOp.INSTANCE;
Callback fixedValue = new DBQueryProxyFixedValue();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(DBQuery.class);
enhancer.setCallbacks(new Callback[]{dbQueryProxy, dbQueryProxy2, noopCb, fixedValue});
enhancer.setCallbackFilter(new CallbackFilter() {
public int accept(Method method) {
if (method.getName().equals("getElement")) {
return 0;
} else if (method.getName().equals("getAllElements")) {
return 1;
} else if (method.getName().equals("methodForNoop")) {
return 2;
} else if (method.getName().equals("methodForFixedValue")) {
return 3;
} else {
return 0;
}
}
});
DBQuery dbQuery = (DBQuery) enhancer.create();
System.out.println("========Inteceptor By DBQueryProxy ========");
System.out.println(dbQuery.getElement("Hello"));
System.out.println();
System.out.println("========Inteceptor By DBQueryProxy2 ========");
System.out.println(dbQuery.getAllElements());
System.out.println();
System.out.println("========Return Original Value========");
System.out.println(dbQuery.methodForNoop());
System.out.println();
System.out.println("========Return Fixed Value========");
System.out.println(dbQuery.methodForFixedValue("myvalue"));
}
}
jdk动态代理和cglib动态代理的区别
底层原理不同 JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类, 在调用具体方法前调用 InvokeHandler 来处理 而 CGLIB 动态代理是利用 ASM 开源包,加载代理对象类的 class 文件 通过修改其字节码生成子类来处理
可作用范围不同 JDK 动态代理只能对实现了接口的类生成代理,而不能针对类 CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 因为是继承,所以该类或方法不能声明成 final 类型
JDK动态代理特点 代理对象必须实现一个或多个接口 以接口的形式接收代理实例,而不是代理类
CGLIB动态代理特点 代理对象不能被 final 修饰 以类或接口形式接收代理实例
JDK与CGLIB动态代理的性能对比 生成代理实例性能:JDK > CGLIB 代理实例运行性能:JDK > CGLIB