spring3.x第七章 基于@AspectJ和Schema的AOP

来源:互联网 发布:node.js硬实战115 pdf 编辑:程序博客网 时间:2024/06/01 19:13

7.1 Spring对AOP的支持

  我们所说的Spring AOP,它包括基于XML配置的AOP和基于@AspectJ注解的AOP,底层都是采用动态代理技术(JDK代理或CGLib代理)。

7.2 JDK5.0注解知识快速进阶

7.2.1 了解注解

  JDK5.0注解,通过Java语言的反射机制获取类中标注的注解,完成特定的功能。
  注解是代码的附属信息,它遵循一个基本原则:注解不能直接干扰程序代码的运行,无论增加或删除注解,代码都能够正常运行。Java语言解释器会忽略这些注解,而由第三方工具负责对注解进行处理。第三方工具可以利用代码中的注解间接控制程序代码的运行,它们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑,而这正是Spring AOP对@AspectJ提供支持所采取的方法。

7.2.2 一个简单的注解类
package com.baobaotao.aspectj.anno;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) //声明注解的保留期限@Target(ElementType.METHOD) //声明可以使用该注解的目标类型public @interface NeedTest { //定义注解    boolean value() default true; //声明注解成员}
7.2.3 使用注解
package com.baobaotao.aspectj.anno;public class ForumService {    @NeedTest(value=true)    public void deleteForum(int forumId){        System.out.println("删除论坛模块:"+forumId);    }    @NeedTest(value=false)    public void deleteTopic(int postId){        System.out.println("删除论坛主题:"+postId);    }}
7.2.4 访问注解

  通过反射获取注解信息,并进行逻辑处理。注意RUNTIME的生存期,所以JVM才会有这个注解信息。

package com.baobaotao.aspectj.anno;import java.lang.reflect.Method;public class TestTool {    public static void main(String[] args) {        Class clazz = ForumService.class;        Method[] methods = clazz.getDeclaredMethods();        System.out.println(methods.length);        for (Method method : methods) {            NeedTest nt = method.getAnnotation(NeedTest.class);            if (nt != null) {                if (nt.value()) {                    System.out.println(method.getName() + "()需要测试");                }else{                    System.out.println(method.getName()+"()不需要测试");                }            }        }    }}

7.3 着手使用@AspectJ

7.3.1 使用前的准备

  aspect.weaver包。

7.3.2 一个简单的例子
package com.baobaotao.aspectj.aspectj;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspect //通过注解标识为一个切面public class PreGreetingAspect {    @Before("execution(* greetTo(..))“) //定义切点和增强类型,greetTo方法可以带任意的入参和任意的返回值    public void beforeGreeting(){        System.out.println("How are you");    }}
7.3.3 如何通过配置使用@AspectJ切面
<!-- 目标Bean -->    <bean id="waiter" class="com.baobaotao.NaiveWaiter" />    <!-- 使用了@AspectJ注解的切面类 -->    <bean class="com.baobaotao.aspectj.aspectj.PreGreetingAspectj" />    <!-- 自动代理创建器,自动将@AspectJ注解切面类织入到目标Bean中 -->    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />

  自动代理创建器,能够将@AspectJ注解切面的自动织入到目标Bean中。
  如果使用基于Schema的aop命名空间进行配置,事情就更简单了:

    <aop:aspectj-autoproxy />    <bean id="waiter" class="com.baobaotao.NaiveWaiter" />    <bean class="com.baobaotao.aspectj.aspectj.PreGreetingAspect" />

7.4 @AspectJ语法基础

7.4.1 切点表达式函数
  execution()

  方法匹配模式串,表示满足某一匹配模式的所有目标类连接点。如exectution(* greetTo(..))表示所有目标类中的greetTo()方法

7.4.2 在函数入参中使用通配符
  *:匹配任意字符,只能匹配上下文中的一个元素
  ..:匹配任意字符,可以匹配上下文中的多个元素
  +:匹配指定类的所有类,跟在类名后面
7.4.3 逻辑运算符
  与操作符,&&,由于&是XML的特殊字符,使用and
  或操作符,||、or
  非操作符,!、not
7.4.4 不同增强类型
  @Before,前置增强
  @AfterReturning,后置增强
  @Around,环绕增强
  @AfterThrowing,抛出增强
  @After,Fianl增强。一般用于释放资源
  @DeclarParents,引介增强
7.4.5 引介增强用法

  希望NaiveWaiter能够同时充当售货员的角色,即通过切面结束为NaiveWaiter新增Seller接口的实现。

package com.baobaotao.aspectj.basic;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.DeclareParents;import com.baobaotao.Seller;import com.baobaotao.SmartSeller;@Aspectpublic class EnableSellerAspect {    @DeclareParents(value="com.baobaotao.NaiveWaiter",            defaultImpl=SmartSeller.class)    public Seller seller;}
    <aop:aspectj-autoproxy />    <bean id="waiter" class="com.baobaotao.NaiveWaiter" />    <bean class="com.baobaotao.aspectj.basic.EnableSellerAspect" />
package com.baobaotao.aspectj.example;import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.baobaotao.NaiveWaiter;import com.baobaotao.Seller;import com.baobaotao.Waiter;import com.baobaotao.aspectj.aspectj.PreGreetingAspect;public class DeclaredParentsTest {    public static void main(String[] args) {        String path = "com/baobaotao/aspectj/basic/AspectJBean.xml";        ApplicationContext act = new ClassPathXmlApplicationContext(path);         Waiter waiter = act.getBean("waiter", Waiter.class);        waiter.greetTo("John");        Seller seller = (Seller) waiter;        seller.sell("Beer", "John");    }}

7.5 切点函数详解

7.5.1 @annotation()

  出错:error the @annotation pointcut expression is only supported at Java 5 compliance level or above。

7.5.2 execution()

  其语法:execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)

  通过方法签名定义切点

  execution(public (..)):第一个代表返回类型,第二个*代表方法名;而..代表任意入参。匹配所有目标类的public方法。
  execution( To(..)):第一个代表返回类型,*To代表任意以To为后缀的方法。

  通过类定义切点

  execution(* com.baobaotao.Waiter.(..)):第一个代表返回任意类型。匹配Waiter接口中的所有方法。
  execution(* com.baobaotao.Waiter+.*(..)):匹配Waiter接口及其所有实现类的方法。

  通过类包定义切点

  execution(* com.baobaotao.*(..)):匹配包下的所有类的所有方法
  execution(* com.baobaotao..*(..)):匹配包、子孙包下所有类的所有方法。
  execution(* com...*Dao.find(..)):匹配包名前缀为com,后缀为Dao的方法,方法名必须以find为前缀。

  通过方法入参定义切点

  execution(* joke(String, int)):匹配joke(String,int)方法
  execution(* joke(String, int)):匹配joke(String,*)方法,第二个参数都行。
  execution(* joke(String, …)):匹配joke(String,多个参数)。
  execution(* joke(Object+)):匹配一个入参,且这个入参是Object类型或该类的子类。

7.5.3 args()和@args()

  args(com.baobaotao.Waiter):匹配参数是Waiter类或其子类。

7.5.4 within()

  最小匹配的单位是类。with(com.baobaotao.*)匹配子类,不包括子孙类。

7.5.5 @within()和@target()

  如果@within(M),M注解的是一个接口,而其子类没有M注解,则不能对子类进行定义切点,因为其都是针对目标类而言,而非针对运行时的引用类型而言。@target()、@annotation()也是。

7.5.6 target()的this()

7.6 @AspectJ进阶

7.6.1 切点复合运算
package com.baobaotao.aspectj.advanced;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class TestApsect {    @After("within(com.baobaotao.*) && execution(* greetTo(..))")    public void greeToFun(){        System.out.println("--greeToFun() executed!--");    }    @Before("!target(com.baobaotao.NaiveWaiter) && execution(* serveTo(..))")    public void notServeInNaiveWaiter(){        System.out.println("--notServeInNaiveWaiter() executed!--");    }    @AfterReturning("target(com.baobaotao.Waiter) || target(com.baobaotao.Seller)")    public void waiterOrSeller(){        System.out.println("--waiterOrSeller() executed!--");    }}
7.6.2 命名切点
package com.baobaotao.aspectj.advanced;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class TestAspect {    @Before("TestNamePointcut.inPkgGreetTo()")    public void pkgGreetTo(){        System.out.println("--pkgGreetTo() executed!--");    }    @Before("!target(com.baobaotao.NaiveWaiter) && TestNamePointcut.inPkgGreetTo()")    public void pkgGreetToNotNaiveWaiter(){        System.out.println("--pkgGreetToNotNaiveWaiter() executed!--");    }}
7.6.3 增强织入的顺序
7.6.4 访问连接点信息
7.6.5 绑定连接点方法入参
7.6.6 绑定代理对象
7.6.7 绑定类注解对象
7.6.8 绑定返回值
7.6.9 绑定抛出的异常

7.7 基于Schema配置切面

7.7.1 一个简单切面的配置
<?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:p="http://www.springframework.org/schema/p"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">    <aop:config proxy-target-class="true">        <aop:aspect ref="adviceMethods">            <aop:before pointcut="target(com.baobaotao.NaiveWaiter) and execution(* greetTo(..))"                method="preGreeting"/>        </aop:aspect>    </aop:config>    <bean id="adviceMethods" class="com.baobaotao.schema.AdviceMethods" />    <bean id="naiveWaiter" class="com.baobaotao.NaiveWaiter" />    <bean id="naughtyWaiter" class="com.baobaotao.NaughtyWaiter" /></beans>
package com.baobaotao.schema;public class AdviceMethods {    public void preGreeting(){        System.out.println("--how are you!--");    }}
7.7.2 配置命名切点
<aop:config proxy-target-class="true">        <aop:aspect ref="adviceMethods">            <aop:pointcut id="greetToPointcut" expression="target(com.baobaotao.NaiveWaiter) and execution(* greetTo(..))" />            <aop:before pointcut=""                method="preGreeting" pointcut-ref="greetToPointcut"/>        </aop:aspect>    </aop:config>
7.7.3 各种增强类型的配置
  后置增强
<aop:config proxy-target-class="true">    <aop:aspect ref="adviceMethods">        <aop:after-returning method="afterReturning"            pointcut="target(com.baobaotao.SmartSeller)" returning="retVal" />    </aop:aspect></aop:config>
public class AdviceMethods{    public void afterReturning(int retVal){    }}
  环绕增强
<aop:around method="aroundMethod" pointcut="target(com.baobaotao.SmartSeller)" />
public class AdviceMethods{    public void aroundMethod(int retVal){    }}
  抛出异常增强
<aop:after-throwing method="afterThrowingMethod" pointcut="target(com.baobaotao.SmartSeller)" throwing="iae"/>
public class AdviceMethods{    public void afterThroingMethod(IllegalArgumentException iae){    }}
  Fianl增强
<aop:after method="afterMethod" pointcut="target(com.baobaotao.SmartSeller)" />
  引介增强
<aop:declare-parents implement-interface="com.baobaotao.Seller"    default-impl="com.baobaotao.SmartSeller"    types-matching="com.baobaotao.Waiter+" />
7.7.4 绑定连接点信息
7.7.5 Advisor配置

  Advisor是Spring中切面概念的对应物,是切点和增强的复合体不过仅包含一个切点和一个增强。

<aop:config>    <aop:advisor advice-ref="testAdvice" pointcut="execution"/></aop:config><bean id="testAdvice" class=""/>

7.8 混合切面类型

  4种定义切面的方式

  基于@AspectJ注解的方式;
  基于<aop:aspect>的方式;
  基于<aop:advisor>
  基于Advisor类的方式;
7.8.2 各种切面类型总结

7.9 JVM Class文件字节码转换基础知识

  到目前为止,我们所接触到的AOP切面织入都是在运行期通过JDK代理或CGLib代理的方式实现的。还可以在类加载期通过字节码编辑的技术,将切面织入到目标类中,这种织入方式称为LTW(Load Time Weaving)。

7.9.1 java.lang.instrument包的工作原理

  该包中有两个能对JVM底层组件进行访问的类

7.9.2 如何向JVM中注册转换器
7.9.3 使用JVM启动参数注册转换器的问题

7.10 使用LTW织入切面

7.10.1 Spring的LoadTimeWeaver
7.10.2 使用LTW织入一个切面
7.10.3 在Tomcat下的配置
7.10.4 在其他Web应用服务器下的配置

7.11 小结

  许多都通过AOP进而伸展到更加深入,偏原理底层的知识。
  JDK5.0的注解知识,是学习@AspectJ的基础。
  掌握切点表达式语法和切点函数是学习@Aspect的重心。
  基于Schema配置的方式继续使用AspectJ的切点表达式和增强定义,基于Schema的配置采用描述@Aspect类所描述的相同信息,知识换一种方法而已。还可以通过复用旧系统已有的Advice并配合使用Aspect的切点表达式。
  Spring还支持LTW的功能,允许通过AspectJ定义切面,在类加载期通过类文件转换器织入切面。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 欠钱败诉没钱还怎么办 学校退款卡丢了怎么办 学校发的卡掉了怎么办 汇款回执单丢了怎么办 大学交学费的卡丢了怎么办 交学费的银行卡丢了怎么办 学校补助卡丢了怎么办 学校交学费的卡丢了怎么办 采购零星材料无发票怎么办 租房合同弄丢了怎么办 买房的合同丢了怎么办 押金的收据丢了怎么办 房东的合同掉了怎么办 个人档案里单位没有放合同怎么办 签的合同掉了怎么办 一方合同弄丢了怎么办 合同丢了怎么办如何补 签了定金合同对方违约怎么办 医学出生证明丢了怎么办 易通行出站未刷怎么办 炭烧酸奶过期了怎么办 西安建行etc坏了怎么办 电机在设备壳体中拔不出来怎么办 公司变更股东不能亲临现场怎么办? 公司股东变更老股东不签字怎么办 公司变更地址股东不签字怎么办 公司变更股份股东不签字怎么办 公司股东离职股东没变更过来怎么办 河南省宋基投资公司欠钱怎么办 曲江楼观2O18怎么办 华旭金卡身份证扫描不了怎么办 水表里有钱没水怎么办? ff14过图速度慢怎么办 想让电表跑的慢怎么办 家里电表突然没有电了怎么办 电表不识别电卡怎么办 家里水表不转了怎么办 车管所体检色弱怎么办 煤气押金单没了怎么办 中国建设银行登录密码忘了怎么办 中国建设银行登录密码忘记了怎么办