菜鸟的成长之路——基于Aspectj的AOP

  对于jdk5.0以后,java提供了注解技术,而Aspectj就是基于注解的AOP技术。那有人可能会问,那基于Aspectj和基于Schema两种谁更好一些呢?那我会说,没有谁好谁不好,这两种形式都比较简洁,就好像用中文写了一个伊索寓言和用英文写了一个伊索寓言一样。

1、基于Schema的AOP都涉及到哪些注解?

  使用Aspectj之前,我们需要maven项目添加一个依赖:

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>

  我们看一下相关的注解:

  • @Aspect,切面类的注解,表明此类是切面类,可以使用增强。
  • @Before,前置增强的注解,参数argNames可以将目标方法的参数获取到前值增强方法的参数上,配合表达式args使用;参数value是切点的表达式。
  • @AfterReturning,后置增强的注解,参数argNames同上;参数pointcut可以引入切点方法;参数returning获取到目标方法的返回值并给增强方法传参。参数value是切点的表达式。
  • @AfterThrowing,异常抛出增强的注解,参数argNames同上;参数pointcut同上;参数value同上;参数throwing获取目标方法的异常并传参给增强。
  • @Around,环绕增强的注解,参数argNames同上,参数value同上。
  • @DeclareParents,引介增强属性级别的注解,value同上,参数defaultImpl是接口的默认实现类。
  • @Pointcut,切点的注解,参数argNames同上,参数value同上。

2、可以可以将这些增强放到同一个代码中体现?

  请看代码:
Lecturer.java(目标类)

package com.spring.test;

/**
 * 讲师类,具有上课方法
 * @author beijingduanluo
 *
 */
public class Lecturer {
    public void classBegin(){
        System.out.println("讲师传授新技术,同学们讨论很激烈!");
    }
}

LecturerAdvice.java(切面)

package com.spring.test;

import org.aspectj.lang.ProceedingJoinPoint;
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.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 增强类
 * @author beijingduanluo
 *
 */
@Aspect
public class LecturerAdvice {
//  引介增强,使用接口类型的属性
    @DeclareParents(value="com.spring.test.Lecturer",defaultImpl=SchoolImpl.class)
    public School school;
    /**
     * 切点方法,避免每个增强都配置切点表达式
     */
    @Pointcut("target(com.spring.test.Lecturer) and execution(public void classBegin())")
    public void pointcut() {}
    /**
     * 前置增强的方法,直接配置切点方法
     */
    @Before("pointcut()")
    public void beforeAdvice() {
        System.out.println("前置增强");
    }
    /**
     * 后置增强的方法,直接配置切点方法
     */
    @AfterReturning("pointcut()")
    public void afterAdvice() {
        System.out.println("后置增强");
    }
    /**
     * 环绕增强的方法,直接配置切点方法
     */
    @Around("pointcut()")
    public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕增强前");
        pjp.proceed();
        System.out.println("环绕增强后");
    }
    /**
     * 异常抛出增强的方法,直接配置切点方法
     */
    @AfterThrowing("pointcut()")
    public void throwsAdvice() {
        System.out.println("异常抛出增强");
    }
}

School.java(目标接口)

package com.spring.test;

public interface School {
    public void setRest(boolean rest);
    public boolean getRest();
}

SchoolImpl.java(目标接口默认实现类)

package com.spring.test;

public class SchoolImpl implements School {

    private boolean rest;
    public void setRest(boolean rest) {
        // TODO Auto-generated method stub
        this.rest = rest;
    }

    public boolean getRest() {
        // TODO Auto-generated method stub
        return rest;
    }

}

ApplicationContext.xml(配置文件)

<?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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!-- 配置目标类 -->
    <bean id="lecturer" class="com.spring.test.Lecturer"></bean>
    <!-- 配置增强类 -->  
    <bean id="advice" class="com.spring.test.LecturerAdvice"></bean>

</beans>

SpringTest.java(测试类)

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.Lecturer;
import com.spring.test.School;

public class SpringTest{

    public static void main(String[] args){
        ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
        Lecturer lecturer = (Lecturer) content.getBean("lecturer");
//      调用目标方法,查看增强
        lecturer.classBegin();
//      测试目标方法使用引介了School接口
        School school = (School) lecturer;
        school.setRest(true);
        System.out.println(school.getRest());
    }
}

控制台

环绕增强前
前置增强
讲师传授新技术,同学们讨论很激烈!
环绕增强后
后置增强
true

  在配置文件中,除了配置目标类的bean和切面的bean,还要使用标签<aop:aspectj-autoproxy>让注解自动代理。

3、spring的总结

  至此为止,我们spring的两个大核心IOC和AOP已经完全学完了,但仅仅是我们的研究告一段落,spring的优美之处已经可圈可点之处远远不止这些。非常多的工程师不断地研究spring的源码,希望能在源码中学到东西,而且他们也在不断地从spring框架中获取到知识。
  spring是java编程的一个纪元,他的外表,他的内层无不令人惊叹。我希望同学们学习spring的步伐不要停止,spring会给我们带来你想不到的成果。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值