`

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/

分享到:
评论

相关推荐

    spring-aop-aspectj(Schema)-case

    在Spring AOP中,AspectJ有两种集成方式:一种是基于注解(@Aspect),另一种是基于XML Schema配置。本案例可能侧重于后者,即XML配置方式。这种方式通常在需要更精细控制或与老项目集成时使用。 描述中提到的"NULL...

    spring入门学习-6、AOP几种配置方式详解.pdf

    Spring 提供了多种方式来支持 AOP 的实现,主要包括基于代理的经典 AOP、Schema-based 的 AOP 和 @AspectJ 注解驱动的 AOP。本文将详细介绍这三种类型的配置方式。 #### 二、基于代理的经典 AOP ##### 2.1 ...

    基于注解配置和使用spring AOP(spring mvc框架)

    1. **启用AOP代理**:在Spring配置文件中,通过&lt;aop:aspectj-autoproxy/&gt;元素启用基于注解的AOP。 ```xml &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=...

    spring-aop实例demo

    这可以通过设置`&lt;aop:aspectj-autoproxy&gt;`或`&lt;aop:config&gt;`元素来完成。例如: ```xml &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...

    Spring AOP + AspectJ in XML 配置示例

    `aop:config`部分则配置了通知,`beforeAdvice`和`afterAdvice`分别对应前置和后置通知,`pointcut-ref`引用了之前定义的切点。 博客中的示例可能包含了如何创建切面类、定义切点表达式、编写通知方法以及如何在XML...

    征服Spring AOP—— Schema

    1. `&lt;aop:config&gt;`:这是Spring AOP配置的根元素,用于开启基于XML的AOP配置。 2. `&lt;aop:pointcut&gt;`:定义一个切入点,即一组连接点。切入点表达式可以用简单的名称引用,也可以使用AspectJ的表达式语言来精确匹配...

    对Spring的AOP标签的支持

    4. `&lt;aop:before&gt;`、`&lt;aop:after&gt;`、`&lt;aop:around&gt;`、`&lt;aop:after-returning&gt;`、`&lt;aop:after-throwing&gt;`:这些标签分别定义了在目标方法执行前、执行后(无论是否抛出异常)、环绕执行、正常返回后和抛出异常后执行...

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

    了解了这些核心概念后,我们可以通过以下步骤来实现Spring AOP: 1. **定义切面类(Aspect)**:创建包含通知方法的类,并使用@Aspect注解标记。 2. **定义切点(Pointcut)**:使用@Pointcut注解声明切点表达式,...

    Spring扫描器—spring组件扫描使用详解

    Spring组件扫描的原理基于Java的注解处理和反射机制。它会遍历指定包及其子包下的所有类,寻找带有特定注解(如@Service、@Component、@Repository、@Controller等)的类,并将这些类实例化为Spring容器中的bean。...

    Spring AOP依赖jar包

    Spring AOP 可以与 AspectJ 集成,使用其编译时或加载时织入功能,以提高性能和减少运行时开销。`AspectJ 1.6.12` 版本的 Jar 包包括了 `aspectjrt.jar` 和 `aspectjweaver.jar`: - **aspectjrt.jar**:AspectJ ...

    Spring AOP详细介绍.docx

    ://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"&gt; &lt;aop:aspectj-autoproxy/&gt; &lt;!-- 其他 Bean 的配置,包括 Operator 切面类和 Service 实现类的配置 --&gt;四...

    spring mvc框架下的aop例子

    1. 在`spring-common.xml`配置文件中,我们需要引入AOP相关的命名空间,并声明一个`&lt;aop:aspectj-autoproxy&gt;`元素。这会告诉Spring容器,我们要启用基于注解的AOP,并代理所有带有切面注解的bean。配置如下: ```...

    spring aop xml实现

    &lt;aop:aspectj-autoproxy/&gt; &lt;!-- 或者针对单个bean --&gt; ``` 6. **使用切面**:最后,正常声明和使用需要AOP增强的业务bean。Spring会自动创建相应的代理对象并应用切面。 通过以上步骤,我们完成了在XML中...

    SpringAOP依赖包

    &lt;aop:aspectj-autoproxy/&gt; ``` 通过上述方式,我们可以轻松地在Spring应用中集成并使用AOP,实现对系统横切关注点的统一管理。同时,AOP的使用还可以提高代码的复用性和模块化,降低系统的复杂度。在实际项目中...

    spring2-aop入门实例教程

    - **基于Schema的配置**:使用XML配置文件来定义Spring AOP的切面、切入点和通知。 - **基于注解的配置**:利用Java注解来简化AOP的配置过程。 - **基于API的方式**:通过编程的方式直接使用Spring AOP API来实现AOP...

    11spring4_aop3.rar

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

    spring1.x使用AOP实例

    最后,Spring 1.x的AOP支持还允许自定义切点表达式,这是通过实现`org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator`类并注册到Spring容器来完成的。这种方式使得基于注解的切面...

    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....

Global site tag (gtag.js) - Google Analytics