在上一章使用了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创建动态代理的更多相关文章

  1. Spring BPP中优雅的创建动态代理Bean

    一.前言 本文章所讲并没有基于Aspectj,而是直接通过Cglib以及ProxyFactoryBean去创建代理Bean.通过下面的例子,可以看出Cglib方式创建的代理Bean和ProxyFact ...

  2. 18.5.1使用Proxy和InvocationHandler创建动态代理

    package d18_5_1; public interface Person { void walk(); void sayHello(String name); } package d18_5_ ...

  3. Java动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

  4. java动态代理浅析

    最近在公司看到了mybatis与spring整合中MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 于是想起了java的动态代理,然后就有了这篇文章 ...

  5. java的静态代理和动态代理(jdk、cglib)

    一.代理模式 代理的概念来自于设计模式中的代理模式,先了解一下代理模式 1.结构图 2.参与者 Subject:接口,定义代理类和实际类的共用接口 RealSubject:实际类,实现Subject这 ...

  6. 代理模式 & Java原生动态代理技术 & CGLib动态代理技术

    第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...

  7. Spring AOP详解 、 JDK动态代理、CGLib动态代理

    AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...

  8. java 笔记(3) —— 动态代理,静态代理,cglib代理

    0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...

  9. JDK动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

随机推荐

  1. win7安装小米8驱动

    首先尝试了小米助手,安装后提示说要会弹窗然后选择确定,但是并没有弹窗:尝试管理员方式运行,依然没有弹框.差评. 正确的姿势是:http://bigota.d.miui.com/tools/xiaomi ...

  2. pinpoint的只是总结

    1,对于拓扑图不显示的原因,可能是hbase版本和pp版本不匹配的原因2,calltree中出现 API-METADATA-NOT-FOUND时是因为HBASE中的元数据被清除了,需要重启应用才可以. ...

  3. python自动化测试框架

    一.环境准备 1.python开发环境, python3.7 2.setuptools基础工具包 3.pip安装包管理工具 4.selenium自动化测试工具  chrom驱动下载地址: http:/ ...

  4. mysql表的连接

    目录 1.笛卡尔积:将两表所有的数据一一对应,生成一张大表 2.连表查询 1.inner join 内连接 2.left join 左连接(left join左边的表为主表,主表记录必须全部显示,辅表 ...

  5. CentOS7下的AIDE入侵检测配置

    一.AIDE的概念 AIDE:Advanced Intrusion Detection Environment,是一款入侵检测工具,主要用途是检查文档的完整性.AIDE在本地构造了一个基准的数据库,一 ...

  6. 使用scrapy框架爬取全书网书籍信息。

    爬取的内容:书籍名称,作者名称,书籍简介,全书网5041页,写入mysql数据库和.txt文件 1,创建scrapy项目 scrapy startproject numberone 2,创建爬虫主程序 ...

  7. 运维笔试Python编程题

    一.用Python语言把列表[1,3,5,7,9]倒序并将元素变为字符类型,请写出多种方法: 第一种方法: list = [1, 3, 5, 7, 9] list.reverse() list2 = ...

  8. DT系统研究之-自定义新建函数

    说说在destoon中,我们二次开发时新建的函数应该放哪里好? 发现部分同学,在学习研究destoon过程中,新建的一些php函数直接放在模块里面,须知这样放置的话,会产生些不良后果. 首先,新建的该 ...

  9. 上下左右居中 无固定高的div

    <style type=“text/css”> #vc { display:table; background-color:#C2300B; width:500px; height:200 ...

  10. Go语言 - 函数 | 作用域 | 匿名函数 | 闭包 | 内置函数

    函数是组织好的.可重复使用的.用于执行指定任务的代码块.本文介绍了Go语言中函数的相关内容. 介绍 Go语言中支持函数.匿名函数和闭包,并且函数在Go语言中属于“一等公民”. 函数可以赋值给变量 函数 ...