Spring中AOP的代理模式

首先,自己实现AOP。

本Demo的目的是要实现调用每个目标方法时,启用方法的性能监控,在目标类方法调用完成时记录方法花费的时间。

1. 先定义接口文件

package com.hik.aopImpl.proxy;

public interface ForumService {
  
  public void removeTopic(int topicId);
  public void removeForum(int forum);
}

2. 实现类代码:

package com.hik.aopImpl.proxy;

public class ForumServiceImpl implements ForumService{

    public void removeTopic(int topicId) {
        //1 开始对该方法进行性能监控
        PerformaceMontior.begin("com.hik.aopImpl.proxy.ForumServiceImpl.removeTopic");
        System.out.println("模拟删除Topic记录:" + topicId);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //2 结束对该方法进行性能监控
        PerformaceMontior.end();
    }

    public void removeForum(int forumId) {
        //1 开始对该方法进行性能监控
        PerformaceMontior.begin("com.hik.aopImpl.proxy.ForumServiceImpl.removeForum");
        System.out.println("模拟删除Forum记录:" + forumId);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //2 结束对该方法进行性能监控
        PerformaceMontior.end();
    }
}


3. 性能监视实现类文件:

package com.hik.aopImpl.proxy;

public class PerformaceMontior {
private static ThreadLocal<MethodPerformace> PerformaceMontior = new ThreadLocal<MethodPerformace>();//通过创建一个ThreadLocal保存调用线程相关的性能监视信息
    public static void begin(String method) {
        System.out.println("Begin Montior ....");
        MethodPerformace mp = new MethodPerformace(method);
        PerformaceMontior.set(mp);
    }

    public static void end() {
        System.out.println("end Montior ....");
        MethodPerformace mp = PerformaceMontior.get();
        mp.printPerformace();
    }

}
package com.hik.aopImpl.proxy;

public class MethodPerformace {
    private long begin;
    private long end;
    private String serviceMethod;
    
    public MethodPerformace(String serviceMethod) {
        this.begin = System.currentTimeMillis();
        this.serviceMethod = serviceMethod;
    }


    public void printPerformace() {
        this.end = System.currentTimeMillis();
        System.out.println(serviceMethod + "一共花费了" + (end - begin) + "毫秒。");
    }

}

4. 测试:

package com.hik.aopImpl.proxy;

import java.lang.reflect.Proxy;

public class TestForumService {
    public static void main(String[] args) {
        ForumService f = new ForumServiceImpl();
        f.removeForum(10);
        f.removeTopic(1012);
    }
}

运行结果:


以上则自己实现了AOP日志记录。但是这些非业务逻辑的兴建空间代码破坏了ForumServiceImpl业务代码的纯粹性。我们希望通过代理的方式,将业务类方法中开启和结束性能监控的这些横切代码从业务类中完全移除,并通过JDK动态代码技术或者CGLib动态代理技术将横切代码动态植入到目标方法相应位置中。

JDK动态代理

JDK的动态代理主要涉及到java.lang.reflect包中的两个类,Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该定义的横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。

首先,我们从业务类ForumServiceImpl中删除性能监控的横切代码。使ForumServiceImpl 只负责具体的业务逻辑(删除ForumServiceImpl中标号为1、2的代码)。

添加JDK动态代码代码:

package com.hik.aopImpl.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PerformanceHandler implements InvocationHandler {
    private Object target;
    
    public PerformanceHandler(Object target) {
        super();
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        PerformaceMontior.begin(target.getClass().getName() + "." + method.getName());
        Object obj = method.invoke(target, args);
        PerformaceMontior.end();
        return obj;
    }

}
相应的,更新测试代码:
package com.hik.aopImpl.proxy;

import java.lang.reflect.Proxy;

public class TestForumService {
    public static void main(String[] args) {
        ForumService f = new ForumServiceImpl();
        
        PerformanceHandler ph = new PerformanceHandler(f);
        ForumService proxy = (ForumService) Proxy.newProxyInstance(f.getClass().getClassLoader(), f.getClass().getInterfaces(), ph);
 
        proxy.removeForum(10);
        proxy.removeTopic(1012);
    }
}
运行结果:

NOTE: JDK 动态代理技术只能使用于有接口,对于没有接口的方法,则只能使用、CGLib代理。

CGLib动态代理

CGLib采用的是非常底层的字节码技术,可以为一个类创建子类。
package com.hik.aopImpl.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {
    
    private Enhancer enhancer = new Enhancer();
    
    public Object getProxy(Class clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        
        return enhancer.create();
    }

    public Object intercept(Object obj, Method method, Object[] arg,
            MethodProxy proxy) throws Throwable {
        PerformaceMontior.begin(obj.getClass().getName() + "." + method.getName());
        Object result = proxy.invokeSuper(obj, arg);
        PerformaceMontior.end();
        return result;
    }

}

更新测试类:
package com.hik.aopImpl.proxy;

import java.lang.reflect.Proxy;

public class TestForumService {
    public static void main(String[] args) {
        ForumService f = new ForumServiceImpl();
        
        CglibProxy cg = new CglibProxy();
        ForumServiceImpl proxy = (ForumServiceImpl) cg.getProxy(ForumServiceImpl.class);
        
        proxy.removeForum(10);
        proxy.removeTopic(1012);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章