您的位置:首页 > 编程语言 > Java开发

spring 第10 天 AOP 面向切面

2017-03-27 11:37 357 查看
AOP(Aspect Orient Programming)也就是 面向切面编程,AOP和OOP 互补


<?xml version="1.0" encoding="UTF-8"?>
<!--  采用 DTD 来约束spring 配置文件
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
-->
<!-- 下面采用 XML Schema 约束-->
<!--default-autowire-candidates="*abc" 该bens 下面的 所以以abc 结尾的 bean 不作为 自动注入的bean  -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> 
<!--自动搜索bean组件,自动搜索切面类--->
<context:component-scan base-package="annotation.model,annotation.aop">
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>

<!-- 这种表示全部使用 注解来配置aop  而且采用cglib来生成代理-->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<!--如果不采用 XML Schema配置方式,则需要配置 下面的bean
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
-->
</beans>


package annotation.aop.point;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

//定义一个切面
@Aspect
public class SystemArchitecture {

/**
* execution(pat1 pat2  pat3  pat4 pat5 pat6)  包含6部分
* pat1 : modifiers-pattern: 方法的修饰符  public default protected private  可以省略
* pat2 : ret-type-pattern: 方法的返回值类型    "*" 表示匹配所有的返回值类型
* pat3 : decaring-type-pattern: 指定方法所属的类   支持通配符  ,可以省略.
* pat4 : name-pattern: 方法名字 ,支持通配符, 可以使用 * 匹配所有方法
* pat5 : param-pattern: 方法 的参数列表 "*" 表示一个任意类型的参数  ".." 任意个数任意类型的参数
* pat6 :throws-pattern: 指定方法声明抛出的异常,支持通配符,可以省略
*
*/

//定义一个 切入点
// 这个表达式 是   pat1=(省略) pat2=*  pat3=annotation.model.impl.Peo* pat4=eat* pat5=(..) pat6=(省略)
@Pointcut("execution(* annotation.model.impl.Peo*.eat*(..))")
public void myPointcut(){

}

//匹配所有 public 方法
@Pointcut("execution(public * * (..))")
public void pintcut1(){

}

//所有set 开头的方法
@Pointcut("execution(* set*(..))")
public void pintcut2(){

}

//所有impl 包下所有类的所有方法
@Pointcut("execution(* annotation.model.impl.*.*(..))")
public void pintcut3(){

}

//所有People类 下的所有 方
@Pointcut("execution(* annotation.model.impl.People.*(..))")
public void pintcut4(){

}

//impl 包中的所有 连接点
@Pointcut("within(annotation.model.impl.*)")
public void pintcut5(){

}
//impl 和 impl 子包中的所有 连接点
@Pointcut("within(annotation.model.impl..*)")
public void pintcut6(){

}

//匹配实现了Perosn接口的目标对象的所有连接点
@Pointcut("this(annotation.model.interfaces.Person)")
public void pintcut7(){

}

//限定目标对象 必须是指定类的实例
@Pointcut("target(annotation.model.interfaces.Person)")
public void pintcut8(){

}

//对连接点的参数类型进行设置
//匹配只接受一个参数.且是 Serializable的所有连	接点
//和 execution的区别是 args 是匹配运行时候的 参数类型
//execution 是匹配方法签名 时候的参数类型
@Pointcut("args(java.io.serializabel)")
public void pintcut9(){

}

//匹配以People的bean 内的连接点
@Pointcut("bean(*People)")
public void pintcut10(){

}

//匹配以stoneAxe 内方法的连接点
@Pointcut("bean(stoneAxe)")
public void pintcut11(){

}

@AfterReturning(pointcut="myPointcut() && args(name,..)",returning="rtv")
public void writeLog(String name,Object rtv){
System.out.println("内部");
System.out.println("参数值name:"+name);
System.out.println("返回值:"+rtv);
}

}


//before 在方法之前执行

package annotation.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class BeforeAdviceTest{

@Before("execution(* annotation.model.impl.*.*(..))")
public void authrity(){
System.out.println("before: 模拟执行权限检查");
}

}


//afterReturning 只有在目标方法执行完后被织入,能够获取方法的返回值,如果中途出现异常了,就不会被增强

package annotation.aop;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AfterRetruningAdviceTest {

//只有 在方法 完成返回后 才能执行 如果中间 出现异常了 是不会执行的
@AfterReturning(returning="rvt",pointcut="execution(* annotation.model.impl.*.*(..))")
public void log(Object rvt){   //如果是Object 则 返回值 为任意类型的 都会被拦截 进行处理
System.out.println("AfterReturning获取目标返回值:"+rvt);
System.out.println("AfterReturning 模拟记录日志功能...");
}

@AfterReturning(returning="rvt",pointcut="execution(* annotation.model.impl.*.*(..))")
public void log(int rvt){ //只拦截  返回值为 int的 方法
System.out.println("AfterReturning 我要的结果:"+rvt);
}
}


//AfterThrowing 主要用于处理程序中未处理的异常,能够指定值增强抛出那些异常的方法

package annotation.aop;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
//@Component
public class AfterThrowingAdviceTest {

//可以  指定只抛出指定的异常  可以对抛出的异常进行处理,但是不能对异常进行完全处理,异常还是会向上抛出
@AfterThrowing(throwing="ex",pointcut="execution(* annotation.model.impl.*.*(..))")
public void doRecoveryActions(Throwable ex){  //NullPointerException ex
System.out.println("AfterThrowing 目标方法中抛出的异常:"+ex);
System.out.println("AfterThrowing 模拟抛出异常后的增强处理...");
}

}


//after  不管目标方法 怎么结束(正常结束,抛出异常结束) 都会织入, 所以类是 finally{}

package annotation.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AfterAdviceTet {

//类是 finally{
//dosomething...
//}
@After("execution(* annotation.model.impl.*.*(..))")
public void release(){
System.out.println("After 模拟方法结束后关闭资源");
}
}


//Around (before + afterReturning) 该增强处理比较强大,

比before强大; 在目标方法执行前,进行增强,可以决定 目标方法 是否执行,和什么时候执行.可以改变目标方法的参数值(也可以阻止目标方法执行)

比afterReturning强大: 可以在方法正常结束后进行增强, 可以改变方法的返回值.

注意:由于 Around 功能强大,因此需要在线程安全的环境下使用,如过用 before 和afterReturning能够解决的问题,就没必要 用 Around 了

package annotation.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AroundAdviceTest {

@Around("execution(* annotation.model.impl.*.*(..))")
public Object proccesTx(ProceedingJoinPoint jp) throws Throwable{
System.out.println("Around :执行目标方法前开始事务");
Object rvt=jp.proceed(new String[]{"被改变的参数"});
System.out.println("Around:执行目标方法之后,模拟结束事务");
return rvt+"Around:新增的内容";
}
}


//访问目标方法的 参数

//Object[] getArgs(): 获取目标方法的参数
//Sigature getSignature()返回被增强法方法的相关信息
//Object getTarget() 返回被织入 增强处理的目标对象
//Object getThis()  返回AOP框架为目标对象生成的代理对象
//==============================================
package annotation.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Order(1)
//@Component
public class FourAdviceTest {
static{
System.out.println("aop 1");
}

@Around("execution(* annotation.model.impl.*.*(..))")
public Object processTx(ProceedingJoinPoint jp) throws Throwable{
System.out.println("-------------------Around增强: 执行目标方法前 ,模拟开始事务....");

//获取执行目标方法的参数
Object[] args=jp.getArgs();
if(args!=null && args.length>0 && args[0].getClass() == String.class){
args[0]="被改变的参数";
}
Object rvt=jp.proceed(args);
System.out.println("Around增强:执行目标方法之后,模拟结束事务...");
return rvt+"新增的内容";
}
@Before("execution(* annotation.model.impl.*.*(..))")
public void authority(JoinPoint jp){
System.out.println("-------------------Before增强处理:");
System.out.println("模拟执行权限检查");
System.out.println("被织入增强处理的目标方法为"+jp.getSignature().getName());
System.out.println("目标方法参数为:"+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为:"+jp.getTarget());
}

@AfterReturning(pointcut="execution(* annotation.model.impl.*.*(..))",returning="rvt")
public void log(JoinPoint jp,Object rvt){
System.out.println("-------------------AfterReturning增强处理");
System.out.println("获取目标返回值:"+rvt);
System.out.println("模拟日志记录功能");
System.out.println("被织入增强处理的目标方法为"+jp.getSignature().getName());
System.out.println("目标方法参数为:"+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为:"+jp.getTarget());
}

@After("execution(* annotation.model.impl.*.*(..))")
public void release(JoinPoint jp){
System.out.println("-------------------After增强处理");
System.out.println("模拟方法结束后,释放资源");
System.out.println("被织入增强处理的目标方法为"+jp.getSignature().getName());
System.out.println("目标方法参数为:"+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为:"+jp.getTarget());
}

}


采用XML配置文件来配置AOP

<?xml version="1.0" encoding="UTF-8"?>
<!--  采用 DTD 来约束spring 配置文件
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
-->
<!-- 下面采用 XML Schema 约束-->
<!--default-autowire-candidates="*abc" 该bens 下面的 所以以abc 结尾的 bean 不作为 自动注入的bean  -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> 
<context:component-scan base-package="annotation.model,annotation.aop">
</context:component-scan>

<!--使用xml来配置AOP -->
<!-- 定义一个切面类
<bean id="fourAdvice" class="annotation.aop.FourAdviceTest"/>
<bean id="fourAdvice1" class="annotation.aop.FourAdviceTest1"/>
-->
<!-- proxy-target-class="false": 默认 采用 com.sun.proxy 代理(表示被代理的类必须是实现了接口,纯 接口实现类)
如果被代理的累是 一个javaBean 则 只能使用 cglib 创建代理
expose-proxy="true" : 决定当前代理是否被暴露在一个ThreadLocal 中以便被目标对象访问。
如果目标对象需要获取代理而且exposeProxy属性被设为 true,
目标对象可以使用AopContext.currentProxy()方法。
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="pt1" expression="execution(* annotation.model.impl.*.*(..))"/>

<aop:aspect id="oneAdvice" ref="fourAdvice" order="1">
<aop:after method="release" pointcut-ref="pt1"/>
<aop:before method="authority" pointcut-ref="pt1"/>
<aop:after-returning returning="rvt" method="log" pointcut-ref="pt1"/>
<!-- 匹配返回值为 String的 -->
<aop:around method="processTx" pointcut="execution(String annotation.model.impl.*.*(..))"/>
</aop:aspect>

<!-- 注解的时候 使用 &&  || !
在使用XML配置的时候 使用  and  or  not
-->
<aop:aspect id="twoAdvice" ref="fourAdvice1" order="2">
<aop:pointcut  id="pt2" expression="execution(* annotation.model.impl.*.*(..)) and args(name)"/>
<aop:before method="authority" pointcut-ref="pt2"/>
</aop:aspect>

<aop:aspect id="errorAdvice" ref="afterThrowingAdviceTest" order="1">
<aop:after-throwing method="doRecoveryActions" pointcut-ref="pt1" throwing="ex"/>
</aop:aspect>
</aop:config>

</beans>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: