面向切面编程(二)

xiaoxiao2021-02-28  101

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) { //切点方法匹配规则,方法名为speaking return "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) { //切点方法匹配规则,方法名为speaking return "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) { //切点方法匹配规则,方法名为speaking return "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

转载请注明原文地址: https://www.6miu.com/read-48675.html

最新回复(0)