JDK和Cglib实现动态代理实例及优缺点分析
Spring AOP使用的核心技术是动态代理,说到动态代理就不得不和设计模式中的代理模式联系起来,通过代理模式我们可以对目标类进行功能增强,在某个方法的执行前后增加一些操作,例如计算方法执行效率、打印日志等。
看下面的例子,我们有一个目标类Target,我们需要在目标类的test方法中增加日志打印功能,这时候我们就可以通过代理模式来实现:
package com.proxy.test; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; class Target {
public void test(){
System.out.println("Target test");
}
} class TargetProxy
{
private Target target;
private Log logger = LogFactory.getLog(TargetProxy.class);
public TargetProxy(Target target) {
this.target = target;
}
public void test()
{
logger.info("*****方法执行前**********");
target.test();
logger.info("*****方法执行后**********");
}
} public class ProxyTest{
public static void main(String[] args) {
Target target = new Target();
TargetProxy proxy = new TargetProxy(target);
proxy.test(); }
}
在上面的例子中我们通过代理类TargetProxy对目标类进行的功能增强,所谓的动态代理就是指在程序运行期间,在内存中动态的生成代理类的字节码并实例化代理对象。
实现方式有两种,一种是通过JDK自带的动态代理,另外一种则是使用Cglib实现。
1.使用JDk实现动态代理
例如在Service层,我们有两个业务逻辑类LoginServiceImpl和UserServiceImpl:
interface LoginService{
public boolean checkUser();
} class LoginServiceImpl implements LoginService{
@Override
public boolean checkUser() {
System.out.println("LoginServiceImpl checkUser");
return false;
}
} interface UserService{
public String getUserName();
} class UserServiceImpl implements UserService{ @Override
public String getUserName() {
System.out.println("UserServiceImpl getUserName");
return null;
} }
我们要对LoginServiceImpl和UserServiceImpl中的方法增加日志打印功能,可以通过Jdk动态代理实现,案例代码如下:
package com.proxy.test.jdk; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; interface LoginService{
public boolean checkUser();
} class LoginServiceImpl implements LoginService{
@Override
public boolean checkUser() {
System.out.println("LoginServiceImpl checkUser");
return false;
}
} interface UserService{
public String getUserName();
} class UserServiceImpl implements UserService{ @Override
public String getUserName() {
System.out.println("UserServiceImpl getUserName");
return null;
} } class ProxyHandler implements InvocationHandler{
private Object target;
private Log logger = LogFactory.getLog(ProxyHandler.class); public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] param)
throws Throwable {
logger.info("*********代理方法执行前************");
Object retObj = method.invoke(target, param);
logger.info("*********代理方法执行后************");
return retObj;
} } public class ProxyTestJDK {
public static void main(String[] args) {
//创建目标对象
LoginService loninService = new LoginServiceImpl();
UserService userService = new UserServiceImpl(); ProxyHandler proxyHandler = new ProxyHandler();
//创建LoginService代理对象
proxyHandler.setTarget(loninService);
LoginService loninService$Proxy = (LoginService) Proxy.newProxyInstance(loninService.getClass().getClassLoader(),
loninService.getClass().getInterfaces(), proxyHandler);
loninService$Proxy.checkUser(); //创建UserService代理对象
proxyHandler.setTarget(userService);
UserService userService$Proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(), proxyHandler);
userService$Proxy.getUserName();
}
}
运行程序输出:
十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
信息: *********代理方法执行前************
LoginServiceImpl checkUser
十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
信息: *********代理方法执行后************
十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
信息: *********代理方法执行前************
UserServiceImpl getUserName
十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
信息: *********代理方法执行后************
2.使用Cglib动态代理实现
对于上面的需求我们也可以通过Cglib实现,具体代码如下:
package com.proxy.test.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
interface LoginService{
public boolean checkUser();
} class LoginServiceImpl implements LoginService{
@Override
public boolean checkUser() {
System.out.println("LoginServiceImpl checkUser");
return false;
}
} interface UserService{
public String getUserName();
} class UserServiceImpl implements UserService{ @Override
public String getUserName() {
System.out.println("UserServiceImpl getUserName");
return null;
} } class CglibProxy implements MethodInterceptor
{
private Log logger = LogFactory.getLog(CglibProxy.class); @Override
public Object intercept(Object proxy, Method method, Object[] params,
MethodProxy methodProxy) throws Throwable {
logger.info("*********代理方法执行前************");
Object retObj = methodProxy.invokeSuper(proxy, params);
logger.info("*********代理方法执行后************");
return retObj;
}
//返回目标对象的代理对象
public Object newProxy(Object target)
{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
enhancer.setClassLoader(target.getClass().getClassLoader());
return enhancer.create();
}
}
public class ProxyTestCglib { public static void main(String[] args) {
//创建目标对象
LoginService loninService = new LoginServiceImpl();
UserService userService = new UserServiceImpl();
CglibProxy proxy = new CglibProxy();
//创建代理对象
LoginService loninService$Proxy = (LoginService)proxy.newProxy(loninService);
UserService userService$Proxy = (UserService)proxy.newProxy(userService);
loninService$Proxy.checkUser();
userService$Proxy.getUserName(); }
}
3.二者优缺点分析
使用JDK动态代理,目标类必须实现的某个接口,如果某个类没有实现接口则不能生成代理对象。
Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型。
从执行效率上看,Cglib动态代理效率较高。
JDK和Cglib实现动态代理实例及优缺点分析的更多相关文章
- JDK 和 CGLib 实现动态代理和区别
JDK 和 CGLib 实现动态代理和区别 在日常的开发中,Spring AOP 是一个非常常用的功能.谈到 AOP,自然离不开动态代理. 那么,基于 JDK 和 CGLib 如何实现动态代理,他们之 ...
- JDK和CGLIB生成动态代理类的区别
关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代 ...
- 【4】JDK和CGLIB生成动态代理类的区别
当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代理:事先写好代理对象类,在 ...
- JDK和CGLIB生成动态代理类的区别(转)
关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代 ...
- jdk与cglib的动态代理
JDK动态代理中包含一个类和一个接口: InvocationHandler接口: public interface InvocationHandler { public Object invoke(O ...
- java面试题之spring aop中jdk和cglib哪个动态代理的性能更好?
在jdk6和jdk7的时候,jdk比cglib要慢: 在jdk8的时候,jdk性能得到提升比cglib要快很多: 结论出自:https://www.cnblogs.com/xuliugen/p/104 ...
- JDK动态代理实现源码分析
JDK动态代理实现方式 在Spring框架中经典的AOP就是通过动态代理来实现的,Spring分别采用了JDK的动态代理和Cglib动态代理,本文就来分析一下JDK是如何实现动态代理的. 在分析源码之 ...
- cglib实现动态代理简单使用
Boss: package proxy.cglib; public class Boss{ public void findPerson() { System.out.println("我要 ...
- jdk自带的动态代理
package com.stone.dp.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Met ...
随机推荐
- vue货币格式化组件、局部过滤功能以及全局过滤功能
一.在这里介绍一个vue的时间格式化插件: moment 使用方法: .npm install moment --save. 2 定义时间格式化全局过滤器 在main.js中 导入组件 import ...
- 【剑指Offer】42、和为S的两个数字
题目描述: 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 输出描述: 对应每个测试案例,输出两个数, ...
- 【剑指Offer】28、数组中出现次数超过一半的数字
题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 例如:输入如下所示的一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过 ...
- C#第二节课
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...
- Proc、宿主变量、指示变量、数组变量、通信区sqlca,oraca ---(day07)
PROC 主要内容: ) proc简介 ) proc程序的开发过程 ) 宿主变量和指示变量 ) 嵌入sql语句 ) 连接数据库 ) 错误处理 ) 数据的存取更新操作 ) 动态sql --------- ...
- 【密码学】RSA加密 kotlin实现方法(支持任意字节长度)
这个编辑器不支持kotlin,尴尬了···· 算了,就用Java来弄吧 val 定义常量 var 定义变量 具体kotlin的开发手册详见:http://www.runoob.com/kotlin/k ...
- BZOJ 3744 Gty的妹子序列 (分块+树状数组+主席树)
题面传送门 题目大意:给你一个序列,多次询问,每次取出一段连续的子序列$[l,r]$,询问这段子序列的逆序对个数,强制在线 很熟悉的分块套路啊,和很多可持久化01Trie的题目类似,用分块预处理出贡献 ...
- CSS 利用transform达到居中效果
<body> <div class="center"> .... </div> </body> 让left和top都是50%,这在水 ...
- 洛谷——P1507 NASA的食物计划
https://www.luogu.org/problem/show?pid=1507#sub 题目背景 NASA(美国航空航天局)因为航天飞机的隔热瓦等其他安 全技术问题一直大伤脑筋,因此在各方压力 ...
- eclipse快捷键深入理解
1.Eclipse 中的重构功能使其成为了一个现代的 Java 集成开发环境 (IDE),而不再是一个普通的文本编辑器.使用重构,您可以轻松更改您的代码,而不必担心对别处造成破坏. 2.Eclipse ...