cglib动态代理和JDK InvocationHandler动态代理的比较
最近这段时间在学习Spring,
而学习Spring的话,其AOP(Aspect Oritened Programming)面向切面编程又是其核心部分。但是实现AOP的时候我们有两种代理机制:cglib和JDK本身的InvocationHandler代理。
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,其实现就需要才cglib.cglib采用了非常底层的字节码技术。原理是:通过字节码技术为一个类创建子类。并且在子类中采用方法拦截的技术拦截所有父类的方法的调用。顺势织入横切逻辑,而jdk与cglib动态代理均是实现spring aop的基础。
cglib创建的动态代理对象性能比JDK创建性能高很多,但是cglib在创建代理对象的时候所花费时间却是比jdk多的多,所以对于单例的对象,其不需要频繁的创建对象,用cglib更合适,反之,用jdk更好。同时,由于cglib是采用动态创建子类的方法,对于final方法,无法进行代理。
下面给出两种代理的具体实现代码:
首先给出cglib代理实现。
package com.clark.cglib;
/**
* cglib动态代理 没有接口的类
* @author Administrator
* 需要被代理的类,也就是父类
*/
public class SayHello {
public void say(){
System.out.println("hello everyone");
}
}
package com.clark.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 创建子类的方法与代理的方法
* @author Administrator
*
*/
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer=new Enhancer();
//getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
/**
* 实现MethodInterceptor接口方法
* intercept()方法拦截所有目标类方法的调用
* obj表示目标类的实例,method为目标类方法的反射对象,
* 为方法的动态入参,proxy为代理类实例。
* proxy.invokeSuper(obj, arg2)通过代理类调用父类中的方法
*/
public Object intercept(Object obj, Method method, Object[] arg2,
MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//对接入点的放行(Spring aop中接入点)也即实现类方法,要是不掉用此方法,则代理类中的say()方法将不会被执行
Object result=proxy.invokeSuper(obj, arg2);
System.out.println("后置代理");
return null;
}
}
package com.clark.cglib;
public class CglibTest {
public static void main(String[] args) {
CglibProxy proxy=new CglibProxy();
//创建生成子类的方式创建代理类
SayHello proxyImpl=(SayHello)proxy.getProxy(SayHello.class);
proxyImpl.say();
}
}
一下是JDK的代理实现代码:其主要是要定义一个接口,去定义一些业务方法
package com.clark.jdkInvacation;
/**
* 目标对象实现的接口,用jdk来生成代理对象一定要实现一个接口
* @author Administrator
*
*/
public interface UserService {
/**
* 目标方法
*/
public void add();
}
package com.clark.jdkInvacation;
/**
* 目标对象
* @author Administrator
*
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("=======add==========");
}
}
package com.clark.jdkInvacation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 实现自己的InvocationHandler
* @author Administrator
*
*/
public class MyInvocationHandler implements InvocationHandler {
//目标对象
private Object target;
/**
* 构造方法
* @param target目标对象
*/
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
/**
* 执行目标对象的方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//在目标对象执行之前简单的标记一下
System.out.println("=====代理前==========");
//执行目标对象的方法
Object result=method.invoke(target, args);
System.out.println("=====代理后==========");
return result;
}
/**
* 获取目标对象的代理对象
* @return 代理对象
*/
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
}
}
package com.clark.jdkInvacation;
/**
* jdk动态代理测试类
* @author Administrator
*
*/
public class ProxyTest {
public static void main(String[] args) {
//实例化目标对象
UserService userService=new UserServiceImpl();
//实例化InvocationHandler
MyInvocationHandler invocationHandler=new MyInvocationHandler(userService);
//根据目标对象生成代理对象
UserService proxy=(UserService)invocationHandler.getProxy();
//调用代理对象的方法
proxy.add();
}
}
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,其实现就需要才cglib.cglib采用了非常底层的字节码技术。原理是:通过字节码技术为一个类创建子类。并且在子类中采用方法拦截的技术拦截所有父类的方法的调用。顺势织入横切逻辑,而jdk与cglib动态代理均是实现spring aop的基础。
cglib创建的动态代理对象性能比JDK创建性能高很多,但是cglib在创建代理对象的时候所花费时间却是比jdk多的多,所以对于单例的对象,其不需要频繁的创建对象,用cglib更合适,反之,用jdk更好。同时,由于cglib是采用动态创建子类的方法,对于final方法,无法进行代理。
下面给出两种代理的具体实现代码:
首先给出cglib代理实现。
package com.clark.cglib;
/**
* cglib动态代理 没有接口的类
* @author Administrator
* 需要被代理的类,也就是父类
*/
public class SayHello {
public void say(){
System.out.println("hello everyone");
}
}
package com.clark.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 创建子类的方法与代理的方法
* @author Administrator
*
*/
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer=new Enhancer();
//getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
/**
* 实现MethodInterceptor接口方法
* intercept()方法拦截所有目标类方法的调用
* obj表示目标类的实例,method为目标类方法的反射对象,
* 为方法的动态入参,proxy为代理类实例。
* proxy.invokeSuper(obj, arg2)通过代理类调用父类中的方法
*/
public Object intercept(Object obj, Method method, Object[] arg2,
MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//对接入点的放行(Spring aop中接入点)也即实现类方法,要是不掉用此方法,则代理类中的say()方法将不会被执行
Object result=proxy.invokeSuper(obj, arg2);
System.out.println("后置代理");
return null;
}
}
package com.clark.cglib;
public class CglibTest {
public static void main(String[] args) {
CglibProxy proxy=new CglibProxy();
//创建生成子类的方式创建代理类
SayHello proxyImpl=(SayHello)proxy.getProxy(SayHello.class);
proxyImpl.say();
}
}
一下是JDK的代理实现代码:其主要是要定义一个接口,去定义一些业务方法
package com.clark.jdkInvacation;
/**
* 目标对象实现的接口,用jdk来生成代理对象一定要实现一个接口
* @author Administrator
*
*/
public interface UserService {
/**
* 目标方法
*/
public void add();
}
package com.clark.jdkInvacation;
/**
* 目标对象
* @author Administrator
*
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("=======add==========");
}
}
package com.clark.jdkInvacation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 实现自己的InvocationHandler
* @author Administrator
*
*/
public class MyInvocationHandler implements InvocationHandler {
//目标对象
private Object target;
/**
* 构造方法
* @param target目标对象
*/
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
/**
* 执行目标对象的方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//在目标对象执行之前简单的标记一下
System.out.println("=====代理前==========");
//执行目标对象的方法
Object result=method.invoke(target, args);
System.out.println("=====代理后==========");
return result;
}
/**
* 获取目标对象的代理对象
* @return 代理对象
*/
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
}
}
package com.clark.jdkInvacation;
/**
* jdk动态代理测试类
* @author Administrator
*
*/
public class ProxyTest {
public static void main(String[] args) {
//实例化目标对象
UserService userService=new UserServiceImpl();
//实例化InvocationHandler
MyInvocationHandler invocationHandler=new MyInvocationHandler(userService);
//根据目标对象生成代理对象
UserService proxy=(UserService)invocationHandler.getProxy();
//调用代理对象的方法
proxy.add();
}
}