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设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...
随机推荐
- shell输出文本颜色
绿地白字 echo -e "\033[42;37m 绿底白字 \033[0m"
- Docke 镜像加速
一.国内获取Docker镜像时,访问 https://hub.docker.com/速度缓慢,只有几十K左右,这种情况可以使用国内的一些docker镜像,国内有些企业做了镜像拷贝工作,这样,我们就可以 ...
- opencv图片压缩视频并读取
import os import cv2 import numpy as np import time path = './new_image/' filelist = os.listdir(path ...
- Mysql【第二课】
- Codeforces A. Game on Tree(期望dfs)
题目描述: Game on Tree time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- Codeforces B. Too Easy Problems
题目描述: time limit per test 2 seconds memory limit per test 256 megabytes input standard input output ...
- unix域套接字
对于本地通信,unix域套接字通信是internet通信速度的2倍
- [Dart] Mixin
Docs Mixins are a way of reusing a class’s code in multiple class hierarchies. void main() { Animal ...
- lxml_time_代理
import requests from pyquery import PyQuery as pq import json import jsonpath from lxml import etree ...
- Java web开发——文件夹的上传和下载
我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 这次项目的需求: 支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,i ...