Spring--AOP思想
上节我们解释了Spring的IOC,其实简单的说IOC是干什么的呢?
IOC和DI就是为一些类中作为对象的属性、集合、属性文件以及一般类型的变量赋值,即注入。
当然只是注入的方式不同例如由setter注入,构造输入,还有就是注解开发;
再本篇中将为大家说明,Spring的第二个核心AOP(面向切面编程)。
首先,什么是面向切面编程?大家应该都学过OOP(面向对象编程),相较于OOP来说,AOP采用的机制就是采取横向抽取的机制来取代传统的纵向继承,举个例子:
举个简单的例子,对于“雇员”这样一个业务实体进行封装,自然是OOP/OOD的任务,我们可以为其建立一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。
同样,对于“权限检查”这一动作片断进行划分,则是AOP的目标领域。而通过OOD/OOP对一个动作进行封装,则有点不伦不类。
换而言之,OOD/OOP面向名词领域,AOP面向动词领域。
一 AOP术语
要想面向切面编程,我们首先得了解一些基本的术语以及几种不同的通知:
1.target目标类:需要被代理的类,我们可以简单的理解为需要服务层中需要公共模块能力的类;
2.JoinPoint连接点:可能被拦截的方法(服务层中所有的方法);
3.CutPoint切入点:需要被增强的方法,也即需要公共能力(事务)的方法,当然查找时不需要的;
4.Advice:通知:它指的就是公共模块的能力;
5.Weaving织入:它是一个虚拟的概念,把通知应用到目标类中创建代理的过程就叫做织入;
6.Proxy代理类:由Spring提供的代理类来完成通知和切入点的整合
7.Aspect切面:连接点和Advice的结合,比如说将日志这种能力加如到tel()这个方法中,就形成一个切面,当你每次调用这个方法的时候,也同时回执行这个dan
注意:Aop用到的地方就是项目的服务层,其实IOC与DI就是用来给服务层中的一些属性复制的;
再上面的七个名词当中Advice有有三中不同的类型:
1.前置通知 MethodBeforeAdvice
2.后置通知:afterreturnAdvice
3.环绕通知:around
接下来将从手动模式,AOP全自动模式,AspectJ模式的开发;
1手动模式
开发步骤分为三大步和三小步
1) 开发通知类
创建类实现MethodBeforeAdvice—构建前置的通知类
创建类实现aftertrRturnAdvice—构建后置的通知类
创建类实现MethodInterceptor—构建环绕的通知类
再具体的场景种一般只使用一种通知;
2) 再服务层创建接口及其实现类
我们一般会在服务层做一些逻辑的判断
再此时我们开发的公共能力通知类和目标类之间是独立的,所以我们应该创建代理类来将二者整合。
3)配置代理类
<!-- 创建通知类对象-->
<bean id="wwww" class="通知类的路径"></bean>
<!-- 创建目标类对象-->
<bean id="AdviceService" class="目标类的包名+实现类类名"></bean>
<!-- 配置代理对象-->
<bean id="Proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- ProxyFactoryBean工厂类在此处返回的不是自己的对象,而是通过其内部的getObject方法得到对应的代理类的对像-->
<!-- 整合目标类-->
<!--<propertyname="target" ref="目标类的id wwww"></property>-->
<!-- 整合通知类-->
<property name="interceptorNames">
<!-- interceptorNames的原由就是其内部参数是可变参数,可以整合多个通知-->
<list>
<value>AfterAdvice</value>
</list>
</property>
<!-- 关联接口-->
<property name="proxyInterfaces">
<!-- proxyInterfaces其内部参数是一个数组,这样就可以关联多个接口-->
<array>
<value>com.qf.service.UserService</value>
<value>com.qf.service.AdviceService</value>
</array>
</property>
</bean>
2 AOP全自动模式
此方法和之前的方法三大步相同,只不过不需要三小步了,而是直接开启AOP全自动编程
具体的配置如下:
<!-- 创建通知类对象-->
<bean id="AfterAdvice" class="通知类的路径"></bean>
<!-- 创建目标类对象-->
<bean id="UserService" class="目标类的包名+实现类类名"></bean>
<aop:config>
<!-- 切入点:找到目标类中的方法:切入点表达式 -->
<aop:pointcut id="cut" expression="execution(*com.ww.service.*.*(..))"></aop:pointcut>
<!-- 让通知和切入点关联 -->
<aop:advisor advice-ref="AfterAdvice"pointcut-ref="cut"></aop:advisor>
</aop:config>
二者的不同之处就在于后者再得到对象时直接使用的目标类对象的id而对于第一个来说使用的时代理类的id即之前的 Proxy。
在这里解释一下切入表达式:
语法:execution(权限修饰符 返回值类型 包名.类名.方法名.(参数))
execution(* com.ww.service.*.*(..))此为一般格式,当然也不乏有些公司按照模块来划分,只需要稍稍变得即可。
3 AspectJ模式的开发
AspectJ的通知类型:@before@afterreturning @around
AspectJ编写的特点:
不需要实现接口
方法名称随意
通过参数来引入切入点
1)编写公共功能通知类
一般前置的参数为 (JoinPoint joinpoint)括号内几位参数下面相同;
后置的参数为 (JoinPoint joinpoint,Object res)
后置的返回参数是可以返回的;
也就是说,当调用有返回值的参数的时候,函数的返回时会到res当中,可以随着通知输出;
环绕的参数为 (ProceedingJoinPoint joinpoint)
但是环绕同时需要手动来调用方法
参数.proceeding();
2)服务层接口及其实现类的编写
1) AOP全自动编程
让通知和切入点关联形成切面;
<bean id="MyAdvice" class="通知类所在包"></bean>
<bean id="UserService" class="目标类的包名+实现类类名"></bean>
<aop:config>(AOP特有的节点)
(关联自定义对象)
<aop:aspect ref="MyAdvice">
(切入点表达式)
<aop:pointcut id="mypoint"expression="execution(*com.ww.service.*.*(..))">
</aop:pointcut>
aop:after-returning method="具体通知类种的方法名" pointcut-ref="切入点表达式的id" returning="res">此处返回值应该与之前方法种的返回值名称相同
</aop:after-returning>
</aop:aspect>
</aop:config>
下一篇将会就注解方式的开发做说明,敬请期待!
版权声明:本文为博主原创文章,未经博主允许不得转载。