Spring之AOP面向切片
来源:互联网 发布:淘宝保证金不见了找谁 编辑:程序博客网 时间:2024/06/05 01:09
一、理论基础:
AOP(Aspectoriented programming)面向切片/服务的编程,在Spring中使用最多的是对事物的处理。而AOP这种思想在程序中很多地方可以使用的,比如说,对某些规则的验证,可以抽象封装到一个模块中,并在该模块中定义一定的使用规则,然后植入到原有的程序中,其实这就是面向切片。这个模块叫做Aspect,定义的规则是pointcut,具体的验证的实现是advice,植入的目标叫TargetObject,切入到目标中的方法叫做joinpint,植入的过程叫weave。
Advice在模块中关注点的具体位置有:前、后或者抛出 Before、After、Throw 三种:
Before Advice
代用之前的处理
After Advice
调用之后的处理
Throw Advice
调用的时候抛出的异常处理
二、实践:
有了理论基础后,重点还是在程序中使用。下面的实例使用注解和配置两种方式,实现对添加用户的方法的验证服务的切入。
1、Anotation注解的方式:
1.首先定义业务逻辑接口UserManager类的方法:
public interface UserManager {public void addUser(String username, String password);public void delUser(int userId);public String findUserById(int userId);public void modifyUser(int userId, String username, String password);}
2.UserManagerImpl类定义接口的实现:
public class UserManagerImpl implements UserManager {public void addUser(String username, String password) {System.out.println("---------UserManagerImpl.add()--------");}public void delUser(int userId) {System.out.println("---------UserManagerImpl.delUser()--------");}public String findUserById(int userId) {System.out.println("---------UserManagerImpl.findUserById()--------");return "张三";}public void modifyUser(int userId, String username, String password) {System.out.println("---------UserManagerImpl.modifyUser()--------");}}
3.SecurityHandler定义要切入的方法:
@Aspectpublic class SecurityHandler {/** * 定义Pointcut,Pointcut的名称为addAddMethod(),此方法没有返回值和参数 * 该方法就是一个标识,不进行调用 */@Pointcut("execution(* add*(..))")private void addAddMethod(){};/** * 定义Advice,表示我们的Advice应用到哪些Pointcut订阅的Joinpoint上 */@Before("addAddMethod()")//@After("addAddMethod()")private void checkSecurity() {System.out.println("-------checkSecurity-------");}}
Anotation注解规则:
@Aspect表示注解的类是抽象的服务方法模块;
@Pointcut定义服务的使用规则,也就是服务方法要应用到目标类中哪些方法上。
@Pointcut("execution(*add*(..))") 第一个*表示不论是否有返回值,所有以add开头的方法,不管是否有参数。
private voidaddAddMethod(){};该方法只是注解模式中一个空的方法体,是一个模式化的方法定义结构,该方法不能有返回值,不能有任何参数,也不能对其进行实现。在Advice中要使用该方法名的标识。
Advice注解checkSecurity()方法,表示该方法是具体的服务方法,使用注解的方式,Advice不出现,而是使用上面理论部分提到的使用@After、@Befor、@Throw来表示,同时要在Advice中关联pointcut中定义的规则。
4.Client客户端调用:
public class Client {public static void main(String[] args) {BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");UserManager userManager = (UserManager)factory.getBean("userManager");userManager.addUser("张三", "123");}}
AspecJ是通过applicationContext.xml文件中的配置,依据SecurityHandler类中的Anotation规则,将服务方法切入到UserManagerImpl类中的方法中的,所以,在客户端使用的时候要通过工厂取得UserManager对象。
5.applicationContext.xml文件中注入AspectJ的AOP服务:
<!-- 启用AspectJ对Annotation的支持 --> <aop:aspectj-autoproxy/> <bean id="userManager" class="com.xxx.spring.UserManagerImpl"/><bean id="securityHandler" class="com.xxx.spring.SecurityHandler"/>
2、配置文件的方式:
注解的方式灵活性不够,不便于业务的修改,下面是使用配置文件的方式:
接口和实现接口类的方法以及在客户端的调用都是一样的,这里略。
1.SecurityHandler类像其他普通类一样,定义服务的方法即可:
public class SecurityHandler {private void checkSecurity() {System.out.println("-------checkSecurity-------");}}
2.重点是applicationContext.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"><bean id="userManager" class="com.bjpowernode.spring.UserManagerImpl"/><bean id="securityHandler" class="com.bjpowernode.spring.SecurityHandler"/><aop:config><aop:aspect id="securityAspect" ref="securityHandler"><!--以add开头的方法 <aop:pointcut id="addAddMethod" expression="execution(* add*(..))"/> --> <!-- com.bjpowernode.spring包下所有的类所有的方法<aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.*(..))"/> --> <aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.add*(..)) || execution(* com.bjpowernode.spring.*.del*(..))"/> <aop:before method="checkSecurity" pointcut-ref="addAddMethod"/></aop:aspect></aop:config></beans>
注意到:
1. Pointcut的匹配规则很灵活,可以使用|| 也可以指定包下的类。
2. 采用配置文件的方法是将服务模块Aspect通过DI注入的方式
3. 配置文件的方式不同于注解的方式,不需要在配置文件中显式的启用AspectJ对Annotation的支持。
3、参数的传递:
在Advice的方法中使用JoinPoint对象可以取得客户端传入的参数值和调用的方法名:
public class SecurityHandler {private void checkSecurity(JoinPoint joinPoint) {for (int i=0; i<joinPoint.getArgs().length; i++) {System.out.println(joinPoint.getArgs()[i]);}System.out.println(joinPoint.getSignature().getName());System.out.println("-------checkSecurity-------");}}
4、使用CGLIB的方式:
如果UserManagerImpl不是实现UserManager接口,那么就需要使用CGLIB的方式,这时候工厂返回的不是UserManager接口对象。
1.UserManagerImpl类:
public class UserManagerImpl {public void addUser(String username, String password) {System.out.println("---------UserManagerImpl.add()--------");}public void delUser(int userId) {System.out.println("---------UserManagerImpl.delUser()--------");}public String findUserById(int userId) {System.out.println("---------UserManagerImpl.findUserById()--------");return "张三";}public void modifyUser(int userId, String username, String password) {System.out.println("---------UserManagerImpl.modifyUser()--------");}}
2.客户端Client:修改返回值
public class Client {public static void main(String[] args) {BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");//UserManager userManager = (UserManager)factory.getBean("userManager");UserManagerImpl userManager = (UserManagerImpl)factory.getBean("userManager");userManager.addUser("张三", "123");}}
这里需要注意的是:
如果UserManagerImpl实现了UserManager接口,那么默认情况下,AspectJ采用jdk的动态代理,返回的是UserManager接口的动态代理对象;
如果UserManagerImpl不是实现了UserManager接口这种方式,那么,AspectJ就会使用CGLIB的方式返回UserManagerImpl的一个CGLIB对象。
Jdk的动态代理和CGLIB实现机制的区别:
Jdk基于接口实现:JDK动态代理对实现了接口的类进行代理
CGLIB基于继承:CGLIB代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以,目标类最好不要使用final声明。
通常情况下,鼓励使用jdk代理,因为业务一般都会抽象出一个接口,而且不用引入新的东西。
如果是遗留的系统,以前没有实现接口,那么只能使用CGLIB。
三、对比动态代理的实现服务切入:
动态代理的实现:接口和实现的方法不变,这里代码略。
1.动态代理类SecurityHandler:
public class SecurityHandler implements InvocationHandler {private Object targetObject;public Object createProxyInstance(Object targetObject) {this.targetObject = targetObject;return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);}public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {checkSecurity();//调用目标方法Object ret = method.invoke(targetObject, args);return ret;}private void checkSecurity() {System.out.println("-------checkSecurity-------");}}
2.客户端Client:
public class Client {public static void main(String[] args) {SecurityHandler hander = new SecurityHandler();UserManager useraManager = (UserManager)hander.createProxyInstance(new UserManagerImpl());useraManager.addUser("张三", "123");}}
对比Spring的IOC和AOP,动态代理有几点是不同的:
1.动态代理使用new的方式创建接口的代理服务类。
2.代理类中将需要添加将服务方法植入到目标类方法中的代码。
3.需要在客户端维护接口类的实现,不够灵活。
四、结尾感触:
Aop面向切片(服务)的编程时一种思想,在学习框架使用的时候,更应该学习这种设计思路,这是架构的基础,也是灵活架构的灵魂所在。
- Spring之AOP面向切片
- java--Spring之AOP面向切片和Spring的简单用法
- AOP(面向切片编程)
- spring之Aop面向切面
- Spring AOP: Spring之面向方面编程
- Spring AOP: Spring之面向方面编程
- Spring AOP: Spring之面向方面编程
- Spring AOP: Spring之面向方面编程
- Method Swizzling、AOP 面向切片编程
- Spring之面向方面编程(AOP)
- Spring之面向方面编程(AOP)
- Spring之AOP实现面向切面编程
- Spring之AOP,面向切面编程
- Spring之AOP面向切面编程
- Spring实践之面向切面编程(AOP)
- Spring boot之AOP面向切面编程
- Spring之AOP(面向切面编程)
- Spring框架之AOP面向切面编程
- 【MFC三天一个游戏】之 局域网黑白棋
- 【C++ STL学习之五】容器set和multiset
- jquery阻止事件冒泡
- 最大子数组问题
- VS2010 重置所有的设置
- Spring之AOP面向切片
- Android中子线程更新主线程UI和ProgressBar的应用
- 打开外部文件-如打开pdf文件
- win32 socket的两个简单的例子
- 思科H.264开源解码器将被用在火狐中
- mongo mapreduce
- 简单线程池-实例
- 表达式计算的问题
- ArcGIS Runtime SDK v10.2新特性