面向切面编程,是spring的一大特点,可以说是spring最独特的特点了(个人认为)。
记得当初学习面向切面编程的时候,可能是面向对象思想根深蒂固了,怎么也理解不了什么叫面向切面。。。
其实对于面向对象学得久的人,刚接触面向切面肯定很难理解,所以辅助记忆很重要。我刚开始记面向切面的时候是这么理解的:
首先,面向对象肯定都熟悉,有不熟悉面向对象的童鞋。。。 建议再去看看java基础。。 然后,还是面相对象,有这么一个对象,需要在这个对象的某一部分增加业务逻辑(切入点),一般什么时候会有切面? 现实中,出现切面的地方一般都会有刀,可以想象一把菜刀,菜刀的面是我们的切面,菜刀上有我们需要注入(还是注入)的方法,然后,我们用菜刀无情的切进对象的切入点(被切对象的方法)。
为什么叫面向切面? 因为当我们要用面向切面的时候,被切的对象往往已经编程完了,不需要动了,我们需要编程,需要修改,需要测试的只是菜刀(切面)而已,所以叫面相切面编程(是不是很容易记住。。)。
这里有我的一个动态代理实现面相切面的一个小例子,有兴趣的童鞋可以看下:http://709002341.iteye.com/admin/blogs/2266317(这是我iteye的博客地址,欢迎大神指点)
下面图文并茂得说一下切面编程的三个步骤:
这是我们的菜刀(切面),首先是面相菜刀(切面)编程:编写好需要切入的各个方法
然后,在配置文件中配置好相应的切入点
然后,一刀下去,程序执行的时候菜刀(切面)就成西瓜(对象)的一部分,被一块执行了。
和现实生活中的切面不同,spring中的切面可以无限使用。
跟前几个例子一样,最后还是用代码说话:
首先说一下场景:见我前几个例子的代码,利用IPrint实现类调用MyBean的print方法打印一个语句。
然后,要实现aop,首先应该编写切面类和切面方法:
package testSpring.business.proxy; import org.aspectj.lang.annotation.Pointcut; /** * DynamicProxy : * @author xuejupo [email protected] * create in 2016-2-16 下午2:45:26 */ public class DynamicProxy { public void doBefore(){ System.out.println("doBefore"); } public void doAfterReturning(){ System.out.println("doAfterReturning"); } public void doAfter(){ System.out.println("doAfter"); } public void doAfterThrowing(){ System.out.println("doAfterThrowing"); } public void doAround(){ System.out.println("doAround"); } }
然后,为注册的MyBean定义一个切入点(就是图文的第二步,在xml文件中定义切入点):
<!-- 为userBean定义一个切面 --> <bean id="aoc" class="testSpring.business.proxy.DynamicProxy" /> <aop:config> <aop:aspect id="aspet" ref="aoc"> <aop:pointcut id="cut" expression="execution (* testSpring.business.bean.MyBean.*(..))" /> <aop:before pointcut-ref="cut" method="doBefore" /> <aop:after-returning pointcut-ref="cut" method="doAfterReturning" returning="obj"/> <aop:after pointcut-ref="cut" method="doAfter" /> <aop:after-throwing pointcut-ref="cut" method="doAfterThrowing" /> <!-- <aop:around pointcut-ref="cut" method="doAround" /> --> </aop:aspect> </aop:config>
然后执行测试代码:
public void testPrintObject7(){ // System.out.println(System.getProperty("java.class.path")); //读取配置文件(将配置文件中的bean加载进内存) ApplicationContext ctx = new ClassPathXmlApplicationContext("/testSpring/resources/applicationContext_proxy.xml"); //获取的实例 IPrint bean = (IPrint)ctx.getBean("userBean"); //调用方法 bean.printObject(); }
结果:
doBefore 打印对象MyBean: doAfterReturning doAfter
上例只是最简单的一个面向切面编程,实际要使用的时候,可能复杂得多(还有注入方式的)。本文只是帮助你理解什么叫面向切面编程,实际使用的时候可以多看看实用教程。
面相切面编程的一般场景是什么? 最主要的一点还是解耦。。。 可见解耦在公司级的编码中是多重要。。。 面相切面编程是将与业务逻辑无关的公共部分抽离开,形成一个横切的关注点(比如权限问题,比如日志问题)。一般情况下,这个横切的关注点在公司里有专人负责,业务逻辑部分的编码人员不需要关心他,公司需要的时候只是配置一下xml文件即可,方便快捷,而且出问题也是切面的负责人负责调试测试,与主逻辑无关。(就像那个图中的菜刀一样,我用菜刀切西瓜还是用菜刀切苹果,菜刀不关心,西瓜也不用关心,握菜刀的人才用关心(公司架构师,或者公司大boss),握菜刀的人负责分配菜刀需要切哪,然后出问题了去告诉造菜刀的人就行,解耦,责任分明,是公司架构中无限追求的事。。。)