首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

spring日志(四):AOP基础

2013-04-21 
spring日记(四):AOP基础package com.springzoo.proxy public interface ForumService {void removeTopic(

spring日记(四):AOP基础
package com.springzoo.proxy; public interface ForumService { void removeTopic(int topicId); void removeForum(int forumId);}

?

package com.springzoo.proxy; public class ForumServiceImpl implements ForumService {     public void removeTopic(int topicId) {        System.out.println("模拟删除Topic记录:"+topicId);        try {            Thread.currentThread().sleep(20);        } catch (Exception e) {            throw new RuntimeException(e);        }    }     public void removeForum(int forumId) {        System.out.println("模拟删除Forum记录:"+forumId);        try {            Thread.currentThread().sleep(40);        } catch (Exception e) {            throw new RuntimeException(e);        }           }}

?

package com.springzoo.proxy; public class PerformanceMonitor {    private static ThreadLocal<MethodPerformace> performaceRecord = new ThreadLocal<MethodPerformace>();    public static void begin(String method) {        System.out.println("begin monitor...");        MethodPerformace mp = performaceRecord.get();        if(mp == null){            mp = new MethodPerformace(method);            performaceRecord.set(mp);        }else{            mp.reset(method);           }    }    public static void end() {        System.out.println("end monitor...");        MethodPerformace mp = performaceRecord.get();        mp.printPerformace();    }}

?

package com.springzoo.proxy; import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method; public class PerformaceHandler implements InvocationHandler {    private Object target;    public PerformaceHandler(Object target){        this.target = target;    }    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        PerformanceMonitor.begin(target.getClass().getName()+"."+ method.getName());        Object obj = method.invoke(target, args);        PerformanceMonitor.end();        return obj;    }}

?

?

?

最后测试下:

package com.springzoo.proxy; public class TestForumService {    public static void main(String[] args) {        // 使用JDK动态代理//      ForumService target = new ForumServiceImpl();//      PerformaceHandler handler = new PerformaceHandler(target);//      ForumService proxy = (ForumService) Proxy.newProxyInstance(target//              .getClass().getClassLoader(),//              target.getClass().getInterfaces(), handler);//      proxy.removeForum(10);//      proxy.removeTopic(1012);                 //使用CGLib动态代理        CglibProxy proxy = new CglibProxy();        ForumService forumService = (ForumService)proxy.getProxy(ForumServiceImpl.class);        forumService.removeForum(10);        forumService.removeTopic(1023);             }}

?

以上的手动编写AOP逻辑和植入非常的不方便,而spring AOP就是要解决这个问题。spring AOP通过Pointcut指定在哪些类的哪些方法上织入横切逻辑,通过Advice描述横切逻辑和方法的织入方位(方法前、方法后、方法前后,跑出异常时)。此外,spring通过Advisor切面将Pointcut和Advice两者组装起来。有了Advisor的信息,spring就可以利用JDK或者CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。

动态代理性能:CGLib的代理对象性能是JDK的10倍,但是创建时间是JDK的8倍,因此对于singleton的对象适合用CGLib,而其他的情况适合用JDK动态代理。注意,CGLib由于采用动态创建子类方式生产代理对象,所以不能对目标类中的final方法进行代理。

》Introduction,引介增强

引介增强可以为目标类创建新的方法和属性,所以其连接点是类级别,通过引介增强我们可以为目标类添加一个接口的实现,通过引介增强我们可以为目标类创建实现某接口的代理。继承DelegatingIntroductionInterceptor即可,覆盖其中的invoke方法。

先定义一个接口类:

package com.springzoo.introduce; public interface Monitorable { void setMonitorActive(boolean active);}

然后自定义Introduction:

package com.springzoo.introduce; import org.aopalliance.intercept.MethodInvocation;import org.springframework.aop.support.DelegatingIntroductionInterceptor; public class ControllablePerformaceMonitor extends DelegatingIntroductionInterceptor implements Monitorable{ private ThreadLocal<Boolean> monitorStatusMap = new ThreadLocal<Boolean>(); public void setMonitorActive(boolean active) { monitorStatusMap.set(active); } public Object invoke(MethodInvocation mi) throws Throwable { Object obj = null; if (monitorStatusMap.get() != null && monitorStatusMap.get()) { PerformanceMonitor.begin(mi.getClass().getName() + "." + mi.getMethod().getName()); obj = super.invoke(mi); PerformanceMonitor.end(); } else { obj = super.invoke(mi); } return obj; }}?

接下来在spring中配置Introduction:

<?xml version="1.0" encoding="UTF-8" ?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="pmonitor" /> <bean id="forumServiceTarget" /> <bean id="forumService" /></beans>

注意:必须指定引介增强所实现的接口,p:inaterfaces,其次由于只能通过为目标类创建子类方式生产引介增强代理,所以必须将proxyTargetClass设为true。还有就是我们没有对ControllerPerformanceMonitor进行线程安全的特殊处理,就必须将singleton属性设为true让ProxyFactoryBean产生prototype的代理,这样会带来严重的性能问题,因为CGLib创建动态代理的性能很低,所以加了个TreadLocal,那么就可以了。

》创建切面Advisor

我们再次给出spring AOP如何定位连接点:

增强Advice提供了连接点方位信息:如织入方法前、后等,而切点进一步描述织入到哪些类的哪些方法上。

spring通过org.springframework.aop.Pointcut接口描述切点,Pointcut由ClassFilter和MethodMatcher构成。

热点排行