Spring Aop

1.AOP概念

AOP采用代理的方式实现

1.1 连接点

程序执行的某个特定位置:如类的开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。

1.2 切点

每个程序类有多个连接点,如拥有两个方法的类,如何定位到感兴趣的连接点,AOP通过切点定位特定连接点。

1.3 增强

增强是织入目标连接点上的一段程序代码。

2. 代理及spring AOP

2.1 JDK 动态代理实例

 a.接口

package com.baobaotao.proxy;

public interface ForumService {

     public void removeTopic(int topicId);

     public void removeForum(int forumId);

}

b.实现接口

package com.baobaotao.proxy;

public class ForumServiceImpl implements ForumService {

    public void removeTopic(int topicId) {

        System.out.println("模拟删除Topic记录:"+topicId);

        try {

                 Thread.currentThread().sleep(20);

        } catch(Exception exp) {

                 throw new RuntimeException(exp);

        }

    }

   public void removeForum(int forumId) {

        System.out.println("模拟删除Forum记录:"+forumId);

        try {

                 Thread.currentThread().sleep(40);

        } catch(Exception exp) {

                 throw new RuntimeException(exp);

        }

    }

}

c1. 记录性能监视信息类

package com.baobaotao.proxy;

public class MethodPerformance {

    private long begin;

    private long end;

    private String serviceMethod;

    public MethodPerformance(String serviceMethod) {

        this.serviceMethod = serviceMethod;

        //记录目标方法开始执行时间

        this.begin = System.currentTimeMillis();

    }

    public void printPerformance() {

        //获取目标方法执行结束时的系统时间,并计算目标类方法执行时间

        end = System.currentTimeMillis() - begin;

        long elapse = end - begin;

        System.out.println(serviceMethod+"花费"+elapse+"毫秒");

    }

}

c2.性能监视实现类

package com.baobaotao.proxy;

public class PerformanceMonitor {

    private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance> ();

            //启动对某一目标方法的性能监控

            public static void begin(String method) {

                System.out.println("begin monitor...");

                MethodPerformance mp = new MethodPerformance(method);

                performanceRecord.set(mp);

            }

            public static void end() {

                 System.out.println("end monitor...");

                 MethodPerformance mp = performanceRecord.get();

                 //打印性能监控结果信息

                 mp.printPerformance();

            }

            

}

d. 将性能监视代码与逻辑代码结合

package com.baobaotao.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class PerformanceHandler implements InvocationHandler {

    //target是目标业务类

    private Object target;

    public PerformanceHandler(Object target) {

        this.target = target;

    }

   public Object invoke(Object proxy,Method method,Object[] args) {

       PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName());

       //通过反射方式调用业务类的目标方法

       Object obj = method.invoke(target,args);

       PerformanceMonitor.end();

       return obj;

  }

}

e.创建代理实例

package com.baobaotao.proxy;

import java.lang.reflect.Proxy;

public class TestForumService {

    //希望被代理的目标业务类

    ForumService target = new ForumServiceImpl();

    //将目标业务类和横切代码编织在一起

    PerformanceHandler handler = new PerformanceHandler(target);

    //创建代理实例

    ForumService proxy = (ForumService)Proxy.newProxyInstance(target.getClass().getClassLoader(),

                                    target.getClass().getInterfaces(),handler);

    //调用代理实例

    proxy.removeForum(10);

    proxy.removeTopic(11);

}

2.2 CGLib动态代理

JDK创建代理有个限制:它创建的代理实例一定要基于接口,CGLib没有这方面的限制

a. CGLib将性能监视代码与逻辑代码结合

package com.baobaotao.proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglig.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[] args,MethodProxy proxy) throws Throwable {

         PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());

         //通过代理类调用父类的方法

         Object result = proxy.invokeSuper(obj,args);

         PerformanceMonitor.end();

         return result;

     }

}

b.测试代理对象的方法

package com.baobaotao.proxy;

import java.lang.reflect.Proxy;

public class TestForumService {

    public static void main(String args[]) {

        CglibProxy proxy = new CglibProxy();

       //通过动态生成子类的方式生成代理类

       ForumServiceImpl forumService = (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);

       forumService.removeForum(10);

       forumService.removeTopic(11);

    }

}

2.3 Spring中的AOP

     Spring AOP通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等),Spring通过切面Advisor将Advice和Pointcut两者组装起来。Spring有各种增强、切点、切面,本文只介绍个小例子。

a1.业务类Waiter

package com.baobaotao.advisor;

public class Waiter {
    public void greetTo(String name) {
        System.out.println("greet to "+name+"...");
        
    }
    public void serveTo(String name) {
        System.out.println("serving "+name+"...");
    }
}

a2.业务类Seller

package com.baobaotao.advisor;

public class Seller {
    public void greetTo(String name) {
        System.out.println("greet to "+name+"...");
    }
}

b.方法的前置增强类

package com.baobaotao.advisor;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object obj)
            throws Throwable {
        String clientName = (String) args[0];
        System.out.println("How are you! Mr."+clientName+".");
    }
}

c.切点

package com.baobaotao.advisor;

import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {

    public boolean matches(Method method, Class clazz) {

        //切点方法匹配规则,方法名为greetTo
        return "greetTo".equals(method.getName());
    }
    
    public ClassFilter getClassFilter() {

        //切点类型匹配规则,为Waiter类或者子类
        return new ClassFilter() {
            public boolean matches(Class clazz) {
                return Waiter.class.isAssignableFrom(clazz);
            }
        };
    }
}

d.在spring核心配置文件中进行配置

<bean id="waiterTarget" class="com.baobaotao.advisor.Waiter"/>

<bean id="sellerTarget" class="com.baobaotao.advisor.Seller"/>

<bean id="greetingAdvice" class="com.baobaotao.advisor.GreetingBeforeAdvice"/>

<!---向切面注入一个前置增强--->

<bean id="greetingAdvisor" class="com.baobaotao.advisor.GreetingAdvisor" p:advice-ref="greetingAdvice"/>

<!---通过一个父bean定义公共的代理信息--->

<bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true"/>

<!---waiter代理--->

<bean id="waiter" parent="parent" p:target-ref="waiterTarget"/>

<!---seller代理--->

<bean id="seller" parent="parent" p:target-ref="sellerTarget"/>

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/seektechnology/blog/848663

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值