面向切面编程(二)

来源:互联网 发布:软件加license 编辑:程序博客网 时间:2024/05/16 16:00

Pointcut 即切入点,用于配置切面的切入位置。由于spring中切入点的粒度是方法级的,因此spring AOP中Pointcut的作用是配置哪些类中哪些方法在用户定义的切入点之内、哪些方法应该被过滤排除。spring的Pointcut分为静态Pointcut、动态Pointcut、和用户自定义的Pointcut。其中静态Pointcut只需考虑类名、方法名;动态Pointcut除此之外还要考虑方法的参数,以便在运行时可以动态的确定切入点的位置。

一、静态Pointcut

通知实现类:

package com.mfc.advice;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;/** * 2017年7月11日00:07:01 * 一个普通的前置通知 * */public class PeopleBeforeAdvice implements MethodBeforeAdvice {public void before(Method method, Object[] objects, Object object) throws Throwable {System.out.println(object.getClass().getSimpleName()+" is "+method.getName()+"!");}}

切面实现类:

package com.mfc.advisor;import java.lang.reflect.Method;import org.springframework.aop.ClassFilter;import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;import com.mfc.models.People;/** * 2017年7月11日00:09:53 * 定义一个切面,过滤那些不需要使用前置通知的方法 * */public class PeopleAdvisor extends StaticMethodMatcherPointcutAdvisor {public boolean matches(Method method, Class<?> class1) {//切点方法匹配规则,方法名为speakingreturn "speaking".equals(method.getName());}//切点类匹配规则,为People类或其子类public ClassFilter getClassFilter(){return new ClassFilter() {public boolean matches(Class<?> arg0) {return People.class.isAssignableFrom(arg0);}};}}

模拟业务类:

public class People {//讲话public void speaking() {System.out.println("嗨,大家好!");}//跑步public void running(){System.out.println("正在跑...");}//吃饭public void eating(){System.out.println("正在吃...");}//死亡public void died(){System.out.println("忧郁而死...");}}

测试类:

package com.mfc.models;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");People people=(People) applicationContext.getBean("proxyFactoryBean");people.speaking();people.running();people.eating();people.died();}}

配置文件:

<bean id="peopleTarget" class="com.mfc.models.People"></bean><bean id="peopleAdvice" class="com.mfc.advice.PeopleBeforeAdvice"></bean><!-- 定义切面 --><bean id="peopleAdvisor" class="com.mfc.advisor.PeopleAdvisor"><!-- 注入前置通知 --><property name="advice" ref="peopleAdvice"></property></bean><bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="interceptorNames"><idref bean="peopleAdvisor"/></property><property name="target" ref="peopleTarget"></property></bean>

二、使用正则表达式的静态Ponintcut

        使用正则表达式后就不需要以上的切面实现类了,可以直接在配置文件中配置:

<bean id="peopleTarget" class="com.mfc.models.People"></bean><bean id="peopleAdvice" class="com.mfc.advice.PeopleBeforeAdvice"></bean><!-- 定义切面 --><bean id="peopleAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="patterns"><list><value>.*ing</value>  <!-- 以ing结尾的方法 --></list></property><!-- 注入前置通知 --><property name="advice" ref="peopleAdvice"></property></bean><bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="interceptorNames"><idref bean="peopleAdvisor"/></property><property name="target" ref="peopleTarget"></property></bean>

三、动态Pointcut

         由于动态切入点除了要考虑方法的名称等静态信息外,还要考虑方法的参数。由于它是动态的,在执行时既要计算方法的静态信息,还要计算其参数,结果也不能被缓存,因此动态切入点要消耗更多的系统资源。

实例:

通知实现类:

public class PeopleBeforeAdvice implements MethodBeforeAdvice {public void before(Method method, Object[] objects, Object object) throws Throwable {System.out.println(object.getClass().getSimpleName()+" is "+method.getName()+"!");}}
切面实现类:

package com.mfc.advisor;import java.lang.reflect.Method;import org.springframework.aop.ClassFilter;import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;import com.mfc.models.People;/** * 2017年7月11日00:09:53 * 定义一个切面,过滤那些不需要使用前置通知的方法 * */public class PeopleAdvisor extends StaticMethodMatcherPointcutAdvisor {public boolean matches(Method method, Class<?> class1) {//切点方法匹配规则,方法名为speakingreturn "speaking".equals(method.getName());}//切点类匹配规则,为People类或其子类public ClassFilter getClassFilter(){return new ClassFilter() {public boolean matches(Class<?> arg0) {return People.class.isAssignableFrom(arg0);}};}}

模拟dao层:

package com.mfc.models;public class People {//讲话public void speaking() {System.out.println("嗨,大家好!");}//跑步public void running(){System.out.println("正在跑...");}//吃饭public void eating(){System.out.println("正在吃...");}//死亡public void died(){System.out.println("忧郁而死...");}}

模拟service业务层;

package com.mfc.models;public class PeopleDelegate {private People people;public void setPeople(People people){this.people=people;}public void living(){people.eating();people.died();}}
测试方法:

package com.mfc.models;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");People people=(People) applicationContext.getBean("people");people.speaking();people.running();people.eating();people.died();PeopleDelegate delegate=new PeopleDelegate();delegate.setPeople(people);delegate.living();}}

spring配置文件:

<bean id="peopleTarget" class="com.mfc.models.People"></bean><bean id="peopleAdvice" class="com.mfc.advice.PeopleBeforeAdvice"></bean><!-- 定义切面 --><bean id="peopleDelegate" class="org.springframework.aop.support.ControlFlowPointcut"><!-- 指定第一个参数为 PeopleDelegate类 --><constructor-arg type="java.lang.Class" value="com.mfc.models.PeopleDelegate"></constructor-arg><!-- 指定第二个参数为living的方法 --><constructor-arg type="java.lang.String" value="living"></constructor-arg></bean><bean id="peopleAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"><property name="pointcut" ref="peopleDelegate"></property><!--指定切点 --><property name="advice" ref="peopleAdvice"></property><!--指定通知  --></bean><bean id="people" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="interceptorNames"><idref bean="peopleAdvisor"/></property><property name="target" ref="peopleTarget"></property></bean>

四、自动代理

       1、使用BeanNameAutoproxyCreator

             前置通知实现类:

public class CheckUser implements MethodBeforeAdvice {public void before(Method method, Object[] objects, Object object) throws Throwable {String username = (String) objects[0]; System.out.println("正在对【"+username+"】用户进行身份检测...");}}
模拟用户登录接口:

public interface UserLogin {public void login(String username);}
实现用户登录接口:

public class UserLoginImpl implements UserLogin {public void login(String username) {System.out.println(username+"正在登陆系统后台...");}}
测试类:

public class BeforeAdviceTest { public static void main(String[] args) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");UserLogin login=(UserLogin) applicationContext.getBean("userlogin");login.login("孟凡诚");}}
spring配置文件:

<!-- 前置通知 --><bean id="checkUser" class="com.mfc.advice.CheckUser"></bean><!-- 被代理的bean --><bean id="userlogin" class="com.mfc.impl.UserLoginImpl"></bean><!-- 自动代理 --><bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><!-- 指定被代理的bean --><property name="beanNames" value="userlogin"></property><!-- 指定通知 --><property name="interceptorNames"><idref bean="checkUser"/></property></bean>

       2、使用DefaultAdvisorAutoProxyCreator

前置通知实现类:

public class PeopleBeforeAdvice implements MethodBeforeAdvice {public void before(Method method, Object[] objects, Object object) throws Throwable {System.out.println(object.getClass().getSimpleName()+" is "+method.getName()+"!");}}
切面实现类:

package com.mfc.advisor;import java.lang.reflect.Method;import org.springframework.aop.ClassFilter;import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;import com.mfc.models.People;/** * 2017年7月11日00:09:53 * 定义一个切面,过滤那些不需要使用前置通知的方法 * */public class PeopleAdvisor extends StaticMethodMatcherPointcutAdvisor {public boolean matches(Method method, Class<?> class1) {//切点方法匹配规则,方法名为speakingreturn "speaking".equals(method.getName());}//切点类匹配规则,为People类或其子类public ClassFilter getClassFilter(){return new ClassFilter() {public boolean matches(Class<?> arg0) {return People.class.isAssignableFrom(arg0);}};}}
模拟dao层:

package com.mfc.models;public class People {//讲话public void speaking() {System.out.println("嗨,大家好!");}//跑步public void running(){System.out.println("正在跑...");}//吃饭public void eating(){System.out.println("正在吃...");}//死亡public void died(){System.out.println("忧郁而死...");}}
测试类:

public class Test {public static void main(String[] args) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");People people=(People) applicationContext.getBean("people");people.speaking();people.running();people.eating();people.died();}}
配置文件:

<bean id="people" class="com.mfc.models.People"></bean><bean id="peopleAdvice" class="com.mfc.advice.PeopleBeforeAdvice"></bean><!-- 配置自动代码创建器 --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean><bean id="peopleAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><!-- 使用正则表达式 --><property name="patterns"><value>.*ing</value><!-- 以ing结尾的方法 --></property><!-- 注入前置通知 --><property name="advice" ref="peopleAdvice"></property></bean>

springaop示例源码下载:http://download.csdn.net/detail/fancheng614/9894591

原创粉丝点击