013 Enhancer创建动态代理
在上一章使用了Enhancer,没有仔细说明代理的问题,在这一章进行详细的说明。
原本想使用cf包的,后来发现使用framework包下的包也没有问题,程序中就一直使用framework中的类。
一:概述
1.说明
CGLIB是一个强大、高性能的字节码生成库,它用于在运行时扩展Java类和实现接口;
本质上它是通过动态的生成一个子类去覆盖所要代理的类(非final修饰的类和方法)。
Enhancer是一个非常重要的类,它允许为非接口类型创建一个JAVA代理,Enhancer动态的创建给定类的子类并且拦截代理类的所有的方法,和JDK动态代理不一样的是不管是接口还是类它都能正常工作。
2.回调接口
net.sf.cglib.proxy.Callback接口:在cglib包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。
net.sf.cglib.proxy.MethodInterceptor接口: 是通用的回调(callback)类型,他经常被AOP用来实现拦截(intercept)方法的调用;
3.关于MethodInterceptor接口的源代码
是Callback的子接口,所以,实现这个接口的类可以用于回调。
package org.aopalliance.intercept; @FunctionalInterface
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation var1) throws Throwable;
}
二:示例
1.结构

2.对象
package com.jun.web.enhancer;
public class HelloWorld {
public String say(boolean say) throws Exception {
System.out.println("Hello Student");
if(!say) {
throw new Exception("回答错误!");
}
return "回答正确!";
}
}
3.回调
package com.jun.web.enhancer; import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class HelloWorldInterceptor implements MethodInterceptor {
/**
*
* 方法描述 当对基于代理的方法回调时,在调用原方法之前会调用该方法
* 拦截对目标方法的调用
*
* @param obj 代理对象
* @param method 拦截的方法
* @param args 拦截的方法的参数
* @param proxy 代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result = null;
try {
//前置通知
before();
result = proxy.invokeSuper(obj, args);
//后置通知
after();
} catch (Exception e) {
//异常通知
exception();
} finally {
//方法返回前通知
beforeReturning();
} return result;
} private void before() {
System.out.println("before method invoke...");
}
private void after() {
System.out.println("after method invoke...");
}
private void exception() {
System.out.println("exception method invoke...");
}
private void beforeReturning() {
System.out.println("beforeReturning method invoke...");
}
}
4.代理
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; //创建Enhancer增强代理类的回调ProxyFactory类
public class ProxyFactory { //要代理的真实对象
private Object obj; public Object createProxy(Object target) {
Enhancer enhancer = new Enhancer();
//设置代理目标
enhancer.setSuperclass(target.getClass());
//设置单一回调对象,在调用中拦截对目标方法的调用
enhancer.setCallback(new HelloWorldInterceptor());
//设置类加载器
enhancer.setClassLoader(target.getClass().getClassLoader()); return enhancer.create();
} }
5.测试
package com.jun.web.enhancer;
public class EnhancerTest {
public static void main(String[] args) throws Exception {
//将要被代理的对象
HelloWorld hello = new HelloWorld();
//代理
ProxyFactory proxy = new ProxyFactory();
//
HelloWorld world = (HelloWorld)proxy.createProxy(hello);
String result = world.say(false);
System.out.println(result);
}
}
6.效果
Connected to the target VM, address: '127.0.0.1:60279', transport: 'socket'
before method invoke...
Hello Student
exception method invoke...
beforeReturning method invoke...
null
Disconnected from the target VM, address: '127.0.0.1:60279', transport: 'socket'
三:其他回调
1.FixedValue
net.sf.cglib.proxy.FixedValue:为提高性能,FixedValue回调对强制某一特定方法返回固定值。
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.FixedValue; public class FixedValueTest {
public static void main(String[] args) throws Exception {
HelloWorld hello = new HelloWorld();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(hello.getClass());
//设置单一回调对象,在调用中拦截对目标方法的调用
enhancer.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "FixedValue";
}
});
//设置类加载器
enhancer.setClassLoader(hello.getClass().getClassLoader()); HelloWorld world = (HelloWorld)enhancer.create();
String result = world.say(false);
System.out.println(result);
}
}
2.效果
Connected to the target VM, address: '127.0.0.1:60379', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:60379', transport: 'socket'
FixedValue Process finished with exit code 0
3.NoOp
net.sf.cglib.proxy.NoOp:NoOp回调把对方法调用直接委派到这个方法在父类中的实现(也可以理解成真实对象直接调用方法);
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.NoOp; public class NoopTest {
public static void main(String[] args) throws Exception {
HelloWorld hello = new HelloWorld();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(hello.getClass());
enhancer.setCallback(NoOp.INSTANCE);
enhancer.setClassLoader(hello.getClass().getClassLoader());
HelloWorld obj = (HelloWorld)enhancer.create();
System.out.println(obj.say(true));
}
}
4.效果
Disconnected from the target VM, address: '127.0.0.1:60418', transport: 'socket'
Hello Student
回答正确! Process finished with exit code 0
5.其他的回调
net.sf.cglib.proxy.LazyLoader:当实际的对象需要延迟装载时,可以使用LazyLoader回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用;
net.sf.cglib.proxy.Dispatcher:Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用;
net.sf.cglib.proxy.ProxyRefDispatcher:ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递;
四:CallbackFilter回调
1.说明
net.sf.cglib.proxy.CallbackFilter允许我们在方法层设置回调(callback),根据我们对方法处理的需求设置不同的回调;如下有一个类Hello,里面有两个方法save和update,save方法需要做前置和后置处理,但是update方法不需要:
2.Hello
package com.jun.web.enhancer;
public class Hello {
public String save() {
System.out.println("save...");
return "save";
}
public String update() {
System.out.println("update...");
return "update";
}
}
3.
package com.jun.web.enhancer;
import org.springframework.cglib.proxy.CallbackFilter;
import java.lang.reflect.Method;
public class CallBackFilterTest implements CallbackFilter {
/**
* 方法返回的值是和callback回调接口数组一一对应的数组下标
*/
@Override
public int accept(Method method) {
String name = method.getName();
if("save".equals(name)) {
return 0;
}
return 1;
}
}
4.测试
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.NoOp; public class CallbackFilterMainTest {
public static void main(String[] args) throws Exception {
Hello hello = new Hello();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(hello.getClass());
enhancer.setCallbackFilter(new CallBackFilterTest());
//创建各个目标代理方法的回调,回调的顺序要与过滤器索引一致
Callback[] callbacks = new Callback[] {new HelloWorldInterceptor(), NoOp.INSTANCE};
//设置单一回调对象,在调用中拦截对目标方法的调用
enhancer.setCallbacks(callbacks);
Hello obj = (Hello)enhancer.create(); System.out.println(obj.update());
System.out.println("=============");
System.out.println(obj.save());
}
}
5.效果
Connected to the target VM, address: '127.0.0.1:60873', transport: 'socket'
update...
update
=============
before method invoke...
Disconnected from the target VM, address: '127.0.0.1:60873', transport: 'socket'
save...
after method invoke...
beforeReturning method invoke...
save Process finished with exit code 0
013 Enhancer创建动态代理的更多相关文章
- Spring BPP中优雅的创建动态代理Bean
一.前言 本文章所讲并没有基于Aspectj,而是直接通过Cglib以及ProxyFactoryBean去创建代理Bean.通过下面的例子,可以看出Cglib方式创建的代理Bean和ProxyFact ...
- 18.5.1使用Proxy和InvocationHandler创建动态代理
package d18_5_1; public interface Person { void walk(); void sayHello(String name); } package d18_5_ ...
- Java动态代理与Cglib库
JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...
- java动态代理浅析
最近在公司看到了mybatis与spring整合中MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 于是想起了java的动态代理,然后就有了这篇文章 ...
- java的静态代理和动态代理(jdk、cglib)
一.代理模式 代理的概念来自于设计模式中的代理模式,先了解一下代理模式 1.结构图 2.参与者 Subject:接口,定义代理类和实际类的共用接口 RealSubject:实际类,实现Subject这 ...
- 代理模式 & Java原生动态代理技术 & CGLib动态代理技术
第一部分.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...
- Spring AOP详解 、 JDK动态代理、CGLib动态代理
AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...
- java 笔记(3) —— 动态代理,静态代理,cglib代理
0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...
- JDK动态代理与Cglib库
JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...
随机推荐
- npm 更换阿里淘宝源
执行命令 npm config set registry https://registry.npm.taobao.org/ 查看是否已经更换成功 npm config get registry
- springboot通过idea打jar包
springboot打jar包 一. 检查pom文件 <packaging>jar</packaging> 二. 切换到maven窗口 三. 先c ...
- Trunk 实现跨交换机 VLAN 通信
当网络中有多台交换机时,位于不同交换机上的相同VLAN的主机之间时如何通信的呢?我们使用Trunk实现跨交换机VLAN通信.还有以太网通道的操作哦. 实验拓扑 两台交换机直连,每台下面再连接两台VPC ...
- python dijkstra 最短路算法示意代码
def dijkstra(graph, from_node, to_node): q, seen = [(0, from_node, [])], set() while q: cost, node, ...
- VS2005编译QT4.8.2
为什么要编译? 因为安装安装版的QT4.8.2,vs2005编译报错. 1.下载QT4.8.2,qt-everywhere-opensource-src-4.8.2.zip,下载vs-AddIn1.1 ...
- Docker创建mysql镜像
原文: https://blog.csdn.net/uk8692/article/details/49386679 https://blog.csdn.net/qq362228416/article/ ...
- IIS 使用 web.config 实现从 http 自动301跳转到 https 的方法
现在很多网站为了安全,开启了 SSL 连接,那么开启 SSL 连接之后,如何将对应的 http 访问自动跳转到 https 上呢?之前介绍了 IIS 用 web.config 做域名的301跳转的方法 ...
- 【Selenium-WebDriver实战篇】基于java的selenium之验证码识别内容
==================================================================================================== ...
- c#中的继承学习总结
c#的继承方法,大体上和c++的类似,但是有点区别的,我这里刚刚初学,因此把重点记录下. 1.派生类继承了父类,那么,如果父类的方法和数据都是public,那么派生类都会继承.派生类可以直接调用父类的 ...
- cifar-10数据集的可视化
import numpy as np from PIL import Image import pickle import os CHANNEL = 3 WIDTH = 32 HEIGHT = 32 ...