`

spring日记(五):基于@AspectJ和Schema的AOP

阅读更多

JDK5.0注解基础知识:

先定义一个简单的注解:

package com.springzoo.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 false;
}

Java新语法规定使用@interface修饰定义注解类,一个注解可以拥有多个成员,成员声明和接口方法声明类似,这里,我们仅仅定义了一个成员,成员有几个限制:

1,成员以无入参无跑出异常方式声明

2,可以通过default指定一个默认值

3,成员类型只能是基本类型以及其包装类、String、Class、enums、注解类型,以及由以上类型的数组类型。

上面的@Retention和@Target称为Java的元注解,它们被Java编译器使用哦,会对注解类的行为产生影响。@Retention(RetentionPolicy.RUNTIME)表示这个注解可以在运行期间被JMV读取。

注解保留期限解释:

* SOURCE:注解信息仅保留在目标类代码的原文件中,对应的字节码文件将不再保留;

* CLASS:注解信息将进入目标类代码的字节码文件中,但类加载器加载字节码文件时不会将注解加载到JVM中,也就是说运行期间不能获得注解信息。

* RUNTIME:注解信息在目标类加载到JMV后依然保留,在运行期间可以通过反射机制读取类中的注解信息。

Target表示该注解可以用在什么地方,有以下几种:

* TYPE:类、接口、注解类、Enum声明处,称为类型注解

* FIELD:类成员变量或常量声明处,称为域值注解

* METHOD:方法声明处,称为方法注解

* PARAMETER:参数声明处,称为参数注解

* CONSTRUCTOR:构造函数声明处

* LOCAL_VARIABLE:局部变量声明出

* ANNOTATION_TYPE:注解类声明处,注意TYPE已经包含了ANNOTATION_TYPE

* PACKAGE:包声明处

下面看一个使用刚刚定义的注解的类:

package com.springzoo.anno;
 
public class ForumService {
    @NeedTest(value=true)
    public void deleteForum(int forumId){
        System.out.println("删除论坛模块:"+forumId);
    }
    /**
     * 
     * @param topicId
     */
    @NeedTest(value=false)
    public void deleteTopic(int topicId){
        System.out.println("删除论坛主题:"+topicId);
    }   
}

自己写工具处理注解:

package com.springzoo.anno;
 
import java.lang.reflect.Method;
 
public class TestTool {
 
    public static void main(String[] args) {
        Class clazz = ForumService.class;
        Method[] methods = clazz.getDeclaredMethods();
        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() + "()不需要测试");
                }
            }
        }
    }
}

》着手使用@AspectJ

使用前准备:spring在处理@AspectJ注解表达式的时候,需要将spring的asm模块添加到类路径中。asm是轻量级的字节码处理框架,因为Java的反射机制无法获取入参名,spring就利用了asm处理@AspectJ中所描述的方法入参名。另外还需引入AspectJ类库:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-asm</artifactId>
    <version>3.1.1.RELEASE</version>
</dependency>
<!-- cglib依赖-->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
<!-- aspecetj-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.6.12</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.12</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>1.6.12</version>
</dependency>

下面开始一个简单的例子:

package com.springzoo.aspectj.example;
 
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class PreGreetingAspect{
    @Before("execution(* greetTo(..))")
    public void beforeGreeting(){
        System.out.println("How are you");
    }
}

可以看到,上面的类就是一普通的POJO类。

再定义一个其他类:

package com.springzoo;
 
import com.springzoo.anno.NeedTest;
 
public class NaiveWaiter implements Waiter {
    public void greetTo(String clientName) {
        System.out.println("NaiveWaiter:greet to "+clientName+"...");
    }   
    @NeedTest
    public void serveTo(String clientName){
        System.out.println("NaiveWaiter:serving "+clientName+"...");
    }
    public void smile(String clientName,int times){
        System.out.println("NaiveWaiter:smile to  "+clientName+ times+"times...");
    }   
}

然后写个测试类:

package com.springzoo.aspectj.example;
 
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
 
import com.springzoo.NaiveWaiter;
import com.springzoo.Waiter;
 
public class AspectJProxyTest {
    public static void main(String[] args) {
        Waiter target = new NaiveWaiter();
        AspectJProxyFactory factory = new AspectJProxyFactory();
        factory.setTarget(target);
        factory.addAspect(PreGreetingAspect.class);
        Waiter proxy = factory.getProxy();
        proxy.greetTo("John");
        proxy.serveTo("John");
    }
}

上面是编程实现,但一般来讲都是配置实现最方便简单:

<?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"
    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:aspectj-autoproxy/>
    <!--bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/-->
    <bean id="waiter" class="com.springzoo.NaiveWaiter" />
    <bean class="com.springzoo.aspectj.example.PreGreetingAspect" />
</beans>

》@AspcetJ的切点函数详解:

* @annotation()

表示标注了某个注解的所有方法

* execution()

这个是最常见的切点函数,其语法如下:

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

execution(public * *(..))

execution(* *To(..))

execution(* com.springzoo.Waiter.*(..))

匹配Waiter接口的所有方法,但仅限于接口中定义的那些方法。

execution(* com.springzoo.Waiter+.*(..))

匹配Waiter接口的所有方法,同时还匹配它实现类的所有其他方法

在类名模式下,.*代表包下的所有类,而..*代表包、子孙包下的所有类。

execution(* com.springzoo.*(..))

execution(* com.springzoo..*(..))

execution(* com..*.*Dao.find*(..))

匹配包名前缀为com的任何包下类名后缀为Dao的所有以find开头的方法

execution(* joke(String,int))

如果入参类型在java.lang包中,可以直接使用类名

execution(* joke(String,*))

两个参数,第一个参数为String类型

execution(* joke(String,..))

第一个参数为String即可

execution(* joke(Object+))

* args() 和 @args()

args()接受一个类名,表示目标类方法入参对象是指定类或者其子类时匹配

args(com.springzoo.Waiter),等价于execution(* *(com.sprongzoo.Waiter+)),也等价于args(com.sprongzoo.Waiter+)

@args()接受一个注解类的类名。

当类继承树中注解点高于入参类型点时候,目标方法不可能匹配切点@args(M)

当类型继承树中注解点低于入参类型点时候,则注解点所在的类及其子孙类作为方法入参时,匹配@args(M)切点。

* within()

通过类匹配模式串声明切点,最小粒度为类

within(com.springzoo.*)

within(com.springzoo..*)

* @within()和@target()

这两个都只接受注解类,其中@target(M)匹配任意标注了@M的目标类,而@within(M)匹配标注了@M的类及其子孙类。由于@within()和@target()以及@annotation()都是针对目标类而言,而非运行时的引用类型而言,那么如果标注了@M的是一个接口,那么所有实现了该接口的类并不匹配@within(M)。

* target() 和 this()

target(M)表示目标类M及其子类匹配切点,类级别

this()是指代理对象的类是否按类型匹配指定类,如果匹配,则代理对象的所有连接点匹配切点。

》@AspectJ进阶

 

本人博客已搬家,新地址为:http://yidao620c.github.io/

分享到:
评论

相关推荐

    跟我学spring3(1-7).pdf

    —— 5.1 概述 5.2 SpEL基础5.3 SpEL语法5.4在Bean定义中使用EL6.1 AOP基础6.2 AOP的HelloWorld6.3 基于Schema的AOP6.4 基于@AspectJ的AOP 6.5 AspectJ切入点语法详解6.6 通知参数6.7 通知顺序6.8 切面实例化模型

    spring-aop-aspectj(Schema)-case

    NULL 博文链接:https://wangxinchun.iteye.com/blog/2074483

    11spring4_aop3.rar

    第三种实现方法—通过注解来实现 签名 注解实现aop &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=... &lt;aop:aspectj-autoproxy/&gt; &lt;/beans&gt;

    Spring AOP源码深度解析:掌握Java高级编程核心技术

    Spring AOP(面向切面编程)是Java高级编程中的重要...Spring AOP的配置方式多样,包括基于接口的配置、schema-based配置和@AspectJ注解配置。通过这些配置方式,开发者可以灵活地实现AOP功能,满足不同场景下的需求。

    springAOP demo 带错误解决文档

    Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/aop] Offending resource: class path resource [beans.xml] at org....

    跟我学spring3(1-7)

    【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我学spring3 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3 【第六章】 AOP 之 6.6 ...

    Spring AOP 基于注解详解及实例代码

    Spring AOP 基于注解详解及实例代码 1.启用spring对@AspectJ注解的支持: &lt;beans xmlns:aop=http://www.springframework.org/schema/aop...&gt; &lt;!--启动支持--&gt; &lt;aop&gt; 也可以配置...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.7. 编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.1.1....

    开发者突击·精通AOP整合应用开发 源码

    Spring AOP:以loC为基础讲解Spring下的AOP开发,讲解了3种AOP的开发方式,即使用@Aspect注释符、基于Schema的配置的开发方式和Spring API的开发方式,最后在实际的Java EE项目中实现5种Spring AOP功能(日志记录器...

    《精通Spring2.X企业应用开发详解》随书源码1-15章

    Spring容器高级主题 第6章 Spring AOP基础 第7章 基于@AspectJ和Schema的 第7章 AOP 第3篇 数据库访问 第8章 Spring对DAO的支持 第9章 Spring的事务管理 第10章 使用Spring JDBC访问数据库 ...

    《精通Spring2.X企业应用开发详解》16-19章

    Spring容器高级主题 第6章 Spring AOP基础 第7章 基于@AspectJ和Schema的 第7章 AOP 第3篇 数据库访问 第8章 Spring对DAO的支持 第9章 Spring的事务管理 第10章 使用Spring JDBC访问数据库 ...

    《精通Spring2.X企业应用开发详解》20-23

    Spring容器高级主题 第6章 Spring AOP基础 第7章 基于@AspectJ和Schema的 第7章 AOP 第3篇 数据库访问 第8章 Spring对DAO的支持 第9章 Spring的事务管理 第10章 使用Spring JDBC访问数据库 ...

    Spring+3.x企业应用开发实战光盘源码(全)

     第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、使用注解进行配置等内容。  第8章:介绍了Spring所提供的DAO封装层,这包括Spring DAO的异常体系、数据访问模板等...

    Spring 2.0 开发参考手册

    6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.7. 编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 ...

    Spring中文帮助文档

    6.3. 基于Schema的AOP支持 6.3.1. 声明一个切面 6.3.2. 声明一个切入点 6.3.3. 声明通知 6.3.4. 引入 6.3.5. 切面实例化模型 6.3.6. Advisor 6.3.7. 例子 6.4. AOP声明风格的选择 6.4.1. Spring AOP还是...

    Spring API

    6.3. 基于Schema的AOP支持 6.3.1. 声明一个切面 6.3.2. 声明一个切入点 6.3.3. 声明通知 6.3.4. 引入 6.3.5. 切面实例化模型 6.3.6. Advisor 6.3.7. 例子 6.4. AOP声明风格的选择 6.4.1. Spring AOP还是...

    Spring.3.x企业应用开发实战(完整版).part2

    第7章 基于@AspectJ和Schema的AOP 7.1 Spring对AOP的支持 7.2 JDK 5.0注解知识快速进阶 7.2.1 了解注解 7.2.2 一个简单的注解类 7.2.3 使用注解 7.2.4 访问注解 7.3 着手使用@AspectJ 7.3.1 使用前的准备 7.3.2 一个...

    spring chm文档

    6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.7. 编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 ...

    使用SSM开发企业级应用第6章课后作业答案.rar

    通过接口实现增强处理是较低版本Spring AOP的做法,如果在一个使用低版本Spring AOP开发的项目上进行升级,可以考虑使用&lt;aop:advisor&gt;复用已经存在的增强类;如果项目采用JDK 5.0以上版本,可以考虑使用@AspectJ注解...

    Spring3.x企业应用开发实战(完整版) part1

    第7章 基于@AspectJ和Schema的AOP 7.1 Spring对AOP的支持 7.2 JDK 5.0注解知识快速进阶 7.2.1 了解注解 7.2.2 一个简单的注解类 7.2.3 使用注解 7.2.4 访问注解 7.3 着手使用@AspectJ 7.3.1 使用前的准备 7.3.2 一个...

Global site tag (gtag.js) - Google Analytics