【一步一步学习spring】spring 基于AspectJ的注解AOP开发

1. AspectJ的简介

  • AspectJ是一个基于java语言的AOP框架
  • spring 2.0以后新增了对AspectJ切点表达式的支持
  • @AspectJ,允许直接在Bean类中定义切面
  • 新版本的spring框架,建议使用AspectJ方式来开发AOP

2. 环境准备

  • 引入xml中aop约束
<?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.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
  • 引入aop AspectJ相关的依赖
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>

3. AspectJ 通知类型列举

  • @Before 前置通知
  • @AfterReturning 后置通知
  • @Around 环绕通知,最强大的,可以阻止方法执行
  • @AfterThrowing 异常抛出通知
  • @After 最终通知,无论是否有异常

4. excution函数语法

  • 通过excution函数,可以定义切点的方法切入
  • 语法:
    • execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
  • 例如:
    • 匹配所有类public方法 execution(public * * ())
    • 匹配指定包下所有类方法 execution(* com.aop.dao.*(..)) 不包含子包中的类
    • execution(* com.aop.dao..*(..)) 包、子孙包下的所有类
    • 匹配指定类所有方法 execution(* com.aop.dao.UserDao.*(..))
    • 匹配实现特定接口所有类的方法 execution(* com.aop.dao.IDao+.*(..))
    • 匹配所有save开头的方法 execution(* save*(..))

5. 栗子

  • 目标类
package com.aop.aspectj;

public class ProductDao {
	public void save(){
		System.out.println("save");
	}
	public void update(){
		System.out.println("update");
	}
	public void delete(){
		System.out.println("delete");
	}
	public void findone(){
		System.out.println("findone");
	}
	public void findall(){
		System.out.println("findall");
		int i = 1 / 0;
	}
}
  • 切面类
package com.aop.aspectj;

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.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspect {

	@Before(value = "execution(* com.aop.aspectj.ProductDao.save(..))")
	public void before(JoinPoint point) {
		System.out.println("==========before========" + point);
	}

	@AfterReturning(value = "execution(* com.aop.aspectj.ProductDao.delete(..))", returning="result")
	public void afterReturning(Object result) {
		System.out.println("===========after returning========" + result);
	}

	@After(value = "execution(* com.aop.aspectj.ProductDao.findone(..))")
	public void after() {
		System.out.println("=========after==============");
	}

	@Around(value = "execution(* com.aop.aspectj.ProductDao.update(..))")
	public Object around(ProceedingJoinPoint point) throws Throwable {
		System.out.println("===========around start===========");
		Object o = point.proceed();
		System.out.println("==========around end========");
		return o;
	}

	@AfterThrowing(value="execution(* com.aop.aspectj.ProductDao.findall(..))", throwing="e")
	public void afterThrowable(Throwable e) {
		System.out.println("===========throw============" + e);
	}
}

  • 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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- 开启aspectj自动代理 -->
	<aop:aspectj-autoproxy/>
	
	<bean id="productDao" class="com.aop.aspectj.ProductDao"/>
	<bean class="com.aop.aspectj.MyAspect"/>
</beans>
  • 调用
package com.aop.aspectj;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-context-aop-aspectj.xml")
public class SpringDemo {

	@Resource(name="productDao")
	private ProductDao dao;
	
	@Test
	public void demo1() {
		dao.save();
		dao.delete();
		dao.update();
		dao.findall();
		dao.findone();
	}
}

6. 通过@Pointcut 为切点命名

  • 在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
  • 切点方法:private void 无参数方法,方法名为切点名
  • 当通知有多个切点,可以使用||进行连接
@Around(value = "pointcut1()||pointcut2()||pointcut3()||pointcut4()||pointcut5()")
public Object around(ProceedingJoinPoint point) throws Throwable {
    System.out.println("===========around start===========");
    Object o = point.proceed();
    System.out.println("==========around end========");
    return o;
}

@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.save(..))")
private void pointcut1() {
}

@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.delete(..))")
private void pointcut2() {
}

@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.findone(..))")
private void pointcut3() {
}

@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.update(..))")
private void pointcut4() {
}

@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.findall(..))")
private void pointcut5() {
}
原文地址:https://www.cnblogs.com/xxxuwentao/p/9600489.html