AOP

来源:互联网 发布:西南大学网络教育是否 编辑:程序博客网 时间:2024/04/29 08:12
      AOP是Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。也可以意为面向行为编程,是函数式编程的一种衍生范型。

AOP中的基本概念和术语。
1、切面(Aspect)
      切面就是一个抽象出来的功能模块的实现,例如上述安全性检查,可以把这个功能从系统中抽象出来,用一个独立的模块描述,这个独立的模块就是切面。
2、连接点(JoinPoint)
      连接点即程序运行过程中的某个阶段点,可以是方法调用、异常抛出等,在这个阶段点可以引入切面,从而给系统增加新的服务功能。
3、通知(Advice)
      通知即在某个连接点所采用的处理逻辑,即切面功能的实际实现。通知的类型包括Before、After、Around以及Throw。
4、切入点(PointCut)
      接入点即一系列连接点的集合,它指明通知将在何时被触发。可以指定能类名,也可以是匹配类名和方法名的正则表达式。当匹配的类或者方法被调用的时候,就会在这个匹配的地方应用通知。
5、 目标对象(Target)
     目标对象就是被通知的对象,在AOP中,目标对象可以专心实现自身的业务逻辑,通知功能可以在程序运行期间自动引入。
6、 代理(Proxy)
      代理是目标对象中使用通知以后创建的对象,这个对象既拥有目标对象的全部功能,而且拥有通知提供的附加功能。

     通知有四种类型,前置通知(Before):在切入点匹配方法之前使用。后置通知(AfterReturning):在切入点匹配方法返回的时候执行。例外通知(AfterThrowing):在切入点匹配的方法执行时抛出异常的时候运行。最终通知(After):无论切入点匹配方法是否正常结束,还是抛出异常结束的,在它结束(finally)后通知。环绕通知(Around):环绕通知既在切入点匹配的方法执行之前又再执行之后运行。并且可以决定这个方法在什么时候执行,如何执行,设置是是否执行。后置通知是在方法return的时候就调用的而最终通知是在try catch finally中的finally块中调用的。所以,正常情况下,return压栈后finlly快执行,然后return值出栈。故最终通知在后置通知前执行。
      Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。如果被代理的目标实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。

示例:
IPersonService.java
package com.zero.service;public interface IPersonService {void save(String name);void update(String name, int personId);String getPersonName(int persinId);}
PersonServiceBean.java
package com.zero.service.impl;import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;import javax.annotation.Resource;import org.springframework.stereotype.Service;import com.zero.dao.IClientDao;import com.zero.dao.impl.ClientDaoBean;import com.zero.service.IPersonService;@Service("personService")public class PersonServiceBean implements IPersonService {private String name = null;public PersonServiceBean() {System.out.println("PersonServiceBean的无参构造函数。。。");}public PersonServiceBean(String name, int age) {System.out.println("PersonServiceBean有参构造函数。。。name = " + name + " age="+ age);}@PostConstructpublic void init() {System.out.println("PersonServiceBean的init()。。。");}@PreDestroypublic void close() {System.out.println("PersonServiceBean的close()。。。");}@Overridepublic void save(String name) {System.out.println("save...");}@Overridepublic void update(String name, int personId) {System.out.println("update...");}@Overridepublic String getPersonName(int persinId) {System.out.println("getPersonName...");return "zero";}}
MyInterceptor.java
package com.zero.interceptor;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.context.annotation.Bean;import org.springframework.stereotype.Component;@Aspect@Component("interceptor")// 声明切面类public class MyInterceptor {@Pointcut("execution (* com.zero.service.impl.PersonServiceBean.*(..))")private void method() {}// 声明一个切入点@Before("method() && args(name)")//前置通知//对有一个String参数的方法才执行前置通知//取得输入参数public void beforeMethod(String name) {System.out.println("***前置通知" + name);}@AfterReturning(pointcut="method()")//后置通知//获取函数返回值public void afterMethod() {System.out.println("***后置通知");}@After("method()")//最终通知public void finallyMethod() {System.out.println("***最终通知");}@AfterThrowing("method()")//例外通知public void throwMethod() {System.out.println("***例外通知");}@Around("method()")public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {System.out.println("进入方法----------");Object result = pjp.proceed();System.out.println("退出方法----------");return result;}}
beans.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"default-lazy-init="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"><!-- 启用AspectJ对Annotation的支持 -->            <aop:aspectj-autoproxy proxy-target-class="true"/> <!—开启自动扫描机制 -->         <context:component-scan base-package="com.zero" /></beans>
      如果在应用中出现:org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'personService' must be of type [com.zero.service.impl.PersonServiceBean], but was actually of type [com.sun.proxy.$Proxy16]这种异常时,是jdk的动态代理不支持类注入,只支持接口方式注入;要想使用用类注入,必须使用cglib代理,推荐使用接口方式注入,基于接口编程的方式。
      解决方法:
     1.aop配置:<aop:config proxy-target-class="true"> </aop:config>   
     2.aspectj配置: <aop:aspectj-autoproxy proxy-target-class="true"/>  
     3.事务annotation配置: <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>  

切入点表达式的使用规则:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
有“?”号的部分表示可省略的,modifers-pattern表示修饰符如public、protected等,ret-type-pattern表示方法返回类型,declaring-type-pattern代表特定的类,name-pattern代表方法名称,param-pattern表示参数,throws-pattern表示抛出的异常。在切入点表达式中,可以使用*来代表任意字符,用..来表示任意个参数。

运行结果:
PersonServiceBean的无参构造函数。。。PersonServiceBean的init()。。。进入方法----------***前置通知kkksave...退出方法----------***最终通知***后置通知进入方法----------update...退出方法----------***最终通知***后置通知进入方法----------getPersonName...退出方法----------***最终通知***后置通知

四类通知在代理中的出现位置简解:
<span style="font-size:14px;">public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//环绕通知PersonServiceBean bean = (PersonServiceBean) this.targetObject;Object result = null; if(bean.getUser()!=null){//..... advice()-->前置通知try {result = method.invoke(targetObject, args);// afteradvice() -->后置通知} catch (RuntimeException e) {//exceptionadvice()--> 例外通知}finally{//finallyadvice(); -->最终通知}}return result;}</span>
0 0
原创粉丝点击