动态代理分为jdk代理和CGLIB代理。
jdk 是接口代理jdk的动态代理调用了Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法。
使用动态代理的五大步骤
1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;
2.通过Proxy.getProxyClass获得动态代理类
3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
4.通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
5.通过代理对象调用目标方法
简单例子如下。
package jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public class JdkProxy {
public static Object createProxy(final Object targetObj, final CustomAspect customAspect) {
// 使用JDK的Proxy类为目标类创建代理对象
return Proxy.newProxyInstance(
// 目标类使用的类加载器
targetObj.getClass().getClassLoader(),
// 目标类实现的接口
targetObj.getClass().getInterfaces(),
// 执行处理器,代理我们的业务逻辑
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 执行切面方法
customAspect.startTransaction();
// 具体逻辑代码执行,返回值为方法执行结果
Object result = method.invoke(targetObj, args);
// 执行切面方法
customAspect.endTrasaction();
// 返回方法执行结果
return result;
}
});
}
}
package jdkproxy;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public interface UserService {
void test();
}
package jdkproxy;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public class UserServiceImpl implements UserService {
@Override
public void test() {
System.out.println("userservice test");
}
}
package jdkproxy;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public class CustomAspect {
public void startTransaction() {
System.out.println("I get datasource here and start transaction");
}
public void endTrasaction() {
System.out.println("I get datasource here and end transaction");
}
}
package jdkproxy;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public class MainProxyJdk {
public static void main(String[] args) {
System.out.println("before Proxy......");
UserService userService = new UserServiceImpl();
userService.test();
System.out.println("After Proxy......");
UserService proxyUserService = (UserService)JdkProxy.createProxy(userService, new CustomAspect());
proxyUserService.test();
}
}
以上是jdk代理的简单例子。
jdk动态代理:代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理。
优点:不需要硬编码接口,代码复用率高。
缺点:只能够代理实现了接口的委托类。
特点:底层使用反射机制进行方法的调用。
CGLIB代理是代理类。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
package cglib;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public class Dao {
public void test() {
System.out.println("dao test");
}
}
package cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public class DaoProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(method.getName() + "-before-");
Object o1 = null;
try {
o1 = methodProxy.invokeSuper(o, objects);
} catch (Exception e) {
e.printStackTrace();
// System.out.println(o + "-" + method.getName() + "-" + objects);
}
System.out.println(method.getName() + "-after");
return o1;
}
}
package cglib;
public interface IMain {
}
package cglib;
import net.sf.cglib.proxy.Enhancer;
/**
* @Author: kevin
* @Date: 2019-03-25
*/
public class Main implements IMain {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dao.class);
enhancer.setCallback(new DaoProxy());
Dao dao = (Dao) enhancer.create();
dao.test();
}
}
以上是CGLIB动态代理的简单例子。
实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口。
这个接口只有一个intercept()方法,这个方法有4个参数:
1)obj表示增强的对象,即实现这个接口类的一个对象;
2)method表示要被拦截的方法;
3)args表示要被拦截方法的参数;
4)proxy表示要触发父类的方法对象;
CGLIB:代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理
优点:可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口。
缺点:不能对final类以及final方法进行代理。
特点:底层将方法全部存入一个数组中,通过数组索引直接进行方法调用。