从上述的实验中能够看出BeanNameAutoProxyCreator对于AOP的实现已经和完美了,可是还有两点不足之处:程序员
1,对于切面的实现比较麻烦,既不一样类型的通知切面要实现不一样的接口,并且一个切面只有一个方法。spring
2,对于切入点的实现也不是很完美,既通知实现的切面对象的方法对于目标对象方法的精确织入要使用不一样的顾问进行包装实现。express
在以上的试验中,咱们不难看出,其实对于切面的的实现就是切面方法向目标对象方法织入的过程。spring-mvc
那么提出两个问题:mvc
1,可不可让一个类去实现不一样类型通知的功能,既一个类中有多个方法,可让咱们指定方法的的通知类型。框架
2,对于切入点的实现能不能规定一种切入点表达式,能够对目标对象的方法进行切入点的指定,免去使用多个顾问对不一样通知包装的麻烦。ide
针对以上两点,AspectJ框架这个框架给出了很好的解决方案,而AspectJ框架又是属于spring框架的一部分。测试
咱们这里依旧经过实验来讲明问题,仍是用以前实验的例子。spa
用于建立目标对象的接口和实现类。code
public interface ICalculatorService { int add(int a,int b); int division(int a ,int b); }
public interface IComparatorService { void comparator(int a,int b); }
public class CalculatorServiceImpl implements ICalculatorService { @Override public int add(int a, int b) { return a+b; } @Override public int division(int a, int b) { return a/b; } }
public class ComparatorServiceImpl implements IComparatorService { @Override public void comparator(int a, int b) { if(a > b){ System.out.println(a+"比"+b+"大"); }else if(a < b){ System.out.println(a+"比"+b+"小"); }else{ System.out.println(a+"等于"+b); } } }
切面的实现类,AspectJ框架容许咱们的切面是一个POJO类,这样就避免了spring框架Api的侵染,另外AspectJ框架比以前多出了一个最终通知,就是无论目标方法执行与否,最终通知的方法都会执行,有点相似finally语句快。
public class MyAspect { //前置通知方法 public void myBefore() { System.out.println("执行前置通知方法"); } // 后置通知方法 public void myAfterReturning() { System.out.println("执行后置通知方法"); } // 环绕通知方法 public Object myAround(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("执行环绕通知方法"); Object[] args = pjp.getArgs(); int a = (int)args[0]; int b = (int)args[1]; if(b == 0){ System.err.println("除数不能为0"); return -1; } if(a == 0){ return 0; } return pjp.proceed(); } // 最终通知 public void myAfter() { System.out.println("执行最终通知"); } }
Xml文件
<?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" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 目标对象 --> <bean id="comparatorServiceTarget" class="com.opensource.service.impl.ComparatorServiceImpl"/> <bean id="calculatorServiceTarget" class="com.opensource.service.impl.CalculatorServiceImpl"/> <!-- 通知 --> <bean id="myAspect" class="com.opensource.service.MyAspect"/> <!-- AOP配置 --> <aop:config> <aop:pointcut expression="execution(* *..service.*.*(..))" id="pointcut1"/> <aop:pointcut expression="execution(* *..ICalculatorService.division(..))" id="pointcut2"/> <aop:aspect ref="myAspect"> <aop:before method="myBefore" pointcut-ref="pointcut1"/> <aop:after-returning method="myAfterReturning" pointcut-ref="pointcut1"/> <aop:around method="myAround" pointcut-ref="pointcut2"/> <aop:after method="myAfter" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config> </beans>
AspectJ框架提供的标签可让咱们指定切面中不一样的方法的通知类型,二切入点表达式则容许咱们对该切面方法要织入spring容器中的那些目标对象,及对象的那些方法(切入点)。对于切入点表达式的使用这里介绍两种最经常使用的:
//指定工程中全部包下子包为service的接口和实现类为切入点
<aop:pointcut expression="execution(* *..service.*.*(..))" id="pointcut1"/>
//指定工程中全部包下接口名为ICalculatorService及其实现类的division方法为切入点 <aop:pointcut expression="execution(* *..ICalculatorService.division(..))" id="pointcut2"/>
你如果想对工程中某个具体的接口或者实现类的方法进行指定就要采用以下作法
这里注意*号后的空格不能少
<aop:pointcut expression="execution(* com.opensource.service.ICalculatorService.division(..))" id="pointcut2"/>
另外切入点表达式一样支持模糊匹配的方式。
测试类:
public class MyTest { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml"); ICalculatorService bean = (ICalculatorService)ac.getBean("calculatorServiceTarget"); IComparatorService bean1 = (IComparatorService)ac.getBean("comparatorServiceTarget"); int division = bean.division(10, 2); System.out.println("两数相除商为:"+division); System.err.println("---------------------------------------------------------"); int add = bean.add(0, 2); System.out.println("两数想加和为:"+add); System.err.println("---------------------------------------------------------"); bean1.comparator(0, 1); } }
实验结果:
AspectJ框架对于Aop的实现配置比较简单,实现上也很灵活,还支持注解式开发,本文用到的式配置式开发,另外还有对于切面方法参数的配置,还有不少点。
最后说一点,咱们做为程序员,研究问题仍是要仔细深刻一点的。当你对原理了解的有够透彻,开发起来也就驾轻就熟了,不少开发中的问题和疑惑也就迎刃而解了,并且在面对其余问题的时候也可作到举一反三。固然在开发中没有太多的时间让你去研究原理,开发中要以实现功能为前提,可等项目上线的后,你有大把的时间或者空余的时间,你大可去刨根问底,深刻的去研究一项技术,为以为这对一名程序员的成长是很重要的事情。