我们都知道,java中的代理分为JDK动态代理和Cglib代理,JDK动态代理是基于反射创建代理对象的,而Cglib是通过字节码技术实现的代理对象创建,使用代理对象的强大作用我们都很清楚,其中spring 中 aop 的核心思想就是基于代理对象的创建,并在切点处织如切面,从而实现aop,今天我们就来实现一下基于JDK动态代理和Cglib代理实现切面功能。
1.AopProxy(interface),定义获取代理对象的方法,具体交由子类实现。
public interface AopProxy {
/**
* 获取代理对象
* @return
*/
Object getInstance();
}
- 具体实现
Jdk动态代理
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK 动态代理
*/
public class JdkDynamicProxy implements AopProxy{
private AspectSupport aspectSupport;
public JdkDynamicProxy(AspectSupport aspectSupport) {
this.aspectSupport = aspectSupport;
}
@Override
public Object getInstance() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
aspectSupport.getTargetSource().targetInterfaces(),new Handler());
}
private class Handler implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodMatcher methodMatcher = aspectSupport.getMethodMatcher();
if (methodMatcher.matches(method)){
MethodInterceptor methodInterceptor = aspectSupport.getMethodInterceptor();
return methodInterceptor.invoke(new ReflectInvocation(args,method,aspectSupport.getTargetSource().getTarget()));
}
return method.invoke(aspectSupport.getTargetSource(),args);
}
}
private class ReflectInvocation implements MethodInvocation {
private Object[] args;
private Method method;
private Object target;
public ReflectInvocation(Object[] args, Method method, Object target) {
this.args = args;
this.method = method;
this.target = target;
}
@Override
public Object[] getArguments() {
return args;
}
@Override
public Object proceed() throws Throwable {
return method.invoke(target,args);
}
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return method;
}
@Override
public Method getMethod() {
return method;
}
}
}
Cglib代理
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
/**
* Cglib 代理
*/
public class CglibProxy implements AopProxy{
private AspectSupport aspectSupport;
public CglibProxy(AspectSupport aspectSupport) {
this.aspectSupport = aspectSupport;
}
@Override
public Object getInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(aspectSupport.getTargetSource().targetClass());
enhancer.setInterfaces(aspectSupport.getTargetSource().targetInterfaces());
enhancer.setCallback(new CglibMethodInterceptor(aspectSupport));
return enhancer.create();
}
// 这个类类似于 InvocationHandler
private class CglibMethodInterceptor implements MethodInterceptor{
private AspectSupport aspectSupport;
public CglibMethodInterceptor(AspectSupport aspectSupport) {
this.aspectSupport = aspectSupport;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
MethodMatcher methodMatcher = aspectSupport.getMethodMatcher();
if (methodMatcher != null && methodMatcher.matches(method)){
return aspectSupport.getMethodInterceptor().invoke(new CglibMethodInvocation(args,method,aspectSupport.getTargetSource().getTarget()));
}
return method.invoke(aspectSupport.getTargetSource().getTarget(),args);
}
}
private class CglibMethodInvocation implements MethodInvocation{
private Object[] args;
private Method method;
private Object target;
public CglibMethodInvocation(Object[] args, Method method, Object target) {
this.args = args;
this.method = method;
this.target = target;
}
@Override
public Object[] getArguments() {
return args;
}
@Override
public Object proceed() throws Throwable {
return method.invoke(target,args);
}
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return method;
}
@Override
public Method getMethod() {
return method;
}
}
}
- 切点接口(Pointcut)
/**
* 切点
*/
public interface Pointcut {
/**
* 类匹配
* @return
*/
ClassFilter getClassFilter();
/**
* 方法匹配
* @return
*/
MethodMatcher getMethodMatcher();
- 类匹配接口
/**
*
* 通过配置的切点表达式进行类匹配
*/
public interface ClassFilter {
/**
* 是否匹配
* @param clazz
* @return
*/
boolean matches(Class<?> clazz);
}
5.方法匹配接口
import java.lang.reflect.Method;
/**
*
* 通过配置的切点表达式进行方法匹配
*/
public interface MethodMatcher {
/**
* 是否匹配
* @param method
* @return
*/
boolean matches(Method method);
}
- 切点,类匹配,方法匹配实现类
注意: 切点表达式采用 aspectj 中的PointcutExpression实现
通过PointcutParser(切点解析器)生成一个PointcutExpression 对象,通过这个对象实现方法和类的匹配功能。
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
/**
* 切点表达式具体实现
* 这个类主要是通过配置的切点表达式实现类和方法的匹配功能
*/
public class AspectJExpressionPointcut implements Pointcut,ClassFilter,MethodMatcher{
private static final Set<PointcutPrimitive> PRIMITIVES = new HashSet<>();
static {
PRIMITIVES.add(PointcutPrimitive.EXECUTION);
}
private final PointcutExpression pointcutExpression;
public AspectJExpressionPointcut(String execution){
PointcutParser parser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(PRIMITIVES);
pointcutExpression = parser.parsePointcutExpression(execution);
}
@Override
public boolean matches(Class<?> clazz) {
return pointcutExpression.couldMatchJoinPointsInType(clazz);
}
@Override
public boolean matches(Method method) {
return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
}
@Override
public ClassFilter getClassFilter() {
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
}
7.TargetSource(封装被代理对象)
/**
* 封装被代理对象,
* JDK 动态代理通过生成接口的实现类创建代理对象
* Cglib通过生成类的子类实现代理对象的创建
*/
public class TargetSource {
private Object target;
public TargetSource(Object target) {
this.target = target;
}
public Object getTarget(){
return target;
}
public Class<?> targetClass(){
return target.getClass();
}
public Class<?>[] targetInterfaces(){
return target.getClass().getInterfaces();
}
}
8.AspectSupport(切面支持类)
import org.aopalliance.intercept.MethodInterceptor;
/**
* 切面支持
* 封装 被代理对象
* MethodInterceptor(方法拦截器,在方法拦截器中实现具体的代理逻辑)
* MethodMatcher(方法匹配器)
*/
public class AspectSupport {
private TargetSource targetSource;
private MethodInterceptor methodInterceptor;
private MethodMatcher methodMatcher;
public AspectSupport(TargetSource targetSource, MethodInterceptor methodInterceptor, MethodMatcher methodMatcher) {
this.targetSource = targetSource;
this.methodInterceptor = methodInterceptor;
this.methodMatcher = methodMatcher;
}
public TargetSource getTargetSource() {
return targetSource;
}
public MethodInterceptor getMethodInterceptor() {
return methodInterceptor;
}
public MethodMatcher getMethodMatcher() {
return methodMatcher;
}
}
9.测试类
UserService
UserServiceInterceptor
UserServiceImpl
Main
public interface UserService {
String sayHello(String name);
}
public class UserServiceImpl implements UserService{
@Override
public String sayHello(String name) {
System.out.println("hello -->" + name);
return "hello -->" + name;
}
}
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
这里在切点处实现了具体的切面逻辑
*/
public class UserServiceInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
long start = System.currentTimeMillis();
try {
return invocation.proceed();
}finally {
long timeTakeUp = System.currentTimeMillis() - start;
System.out.println("方法执行耗时-->" + timeTakeUp);
}
}
}
import aop.test.UserService;
import aop.test.UserServiceImpl;
import aop.test.UserServiceInterceptor;
public class Main {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
String execution = "execution(* aop.test.UserService.*(..))";
AspectSupport aspectSupport = new AspectSupport(
new TargetSource(userService),
new UserServiceInterceptor(),
new AspectJExpressionPointcut(execution)
);
//UserService instance = (UserService)new CglibProxy(aspectSupport).getInstance();
UserService instance = (UserService)new JdkDynamicProxy(aspectSupport).getInstance();
String result = instance.sayHello("夏天");
System.out.println("result -- >" + result);
}
}
从上面的结果可以看到,直接生成(new UserServuiceImpl)的UserService对象被代理对象代理了,并且在具体的切点处加入了切面逻辑。