springAOP--学习和理解--用注解方式完成面向切面编程

版权声明:本文为博主原创文章,经博主允许,可自由共享,尽量不要用于商业用途。 https://blog.csdn.net/matrixbbs/article/details/89084446

1 创建项目

在这里插入图片描述

2 案例读解

音乐会整个流程
入场。。。检票。。。入座。。。看表演。。。鼓掌。。。散场

3 业务分解

核心业务:表演
切面业务:检票,入座,鼓掌

4 核心代码

pom.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.zfh</groupId>
	<artifactId>springAOP-4</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springAOP-4</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		
		<!-- AOP依赖 start -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        
        <!-- AspectJ start-->
        <dependency>
          <groupId>org.aspectj</groupId>
          <!-- runtime包 -->
          <artifactId>aspectjrt</artifactId>
          <version>1.6.11</version>
        </dependency>
        <dependency>
          <groupId>org.aspectj</groupId>
          <!-- 织入包 -->
          <artifactId>aspectjweaver</artifactId>
          <version>1.6.11</version>
        </dependency>
        <!-- 用于动态代理,基于类的代理 -->
        <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>2.1</version>
        </dependency>
        <!-- AspectJ end-->
        
        <!-- AOP依赖 end -->
		
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

AppConfig.java

package com.fhzheng.demo.concert;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

	/**
	 * 声明核心业务实现bean,交给容器
	 * @return
	 */
	@Bean
	public Concert concert() {
		return new Concert();
	}
	
	/**
	 * 声明切面业务实现bean,交给容器
	 * @return
	 */
	@Bean
	public Audience audience() {
		return new Audience();
	}
}


Audience.java

package com.fhzheng.demo.concert;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 切面定义,即业务周边增强
 * @author fhzheng
 *
 */
@Aspect
public class Audience {

	@Pointcut("execution(* com.fhzheng.demo.concert.Performance.*(..))")
	public void perform() {}
	
	@Before("perform()")
	public void checkIn() {
		System.out.println("观众需检票入场。。。");
	}
	
	@Before("perform()")
	public void takeSeats() {
		System.out.println("观众入座。。。");
	}
	
	@AfterReturning("perform()")
	public void applause() {
		System.out.println("表演精彩,观众欢呼...");
	}
	
	@AfterThrowing("perform()")
	public void demandRefund() {
		System.out.println("表演出差错,观众退款...");
	}
}

concert.java

package com.fhzheng.demo.concert;

/**
 * 核心业务实现
 * @author fhzheng
 *
 */
public class Concert implements Performance{

	@Override
	public void perform() {

		System.out.println("音乐会进行中...");
	}

}

Performance.java

package com.fhzheng.demo.concert;

/**
 * 核心业务定义
 * @author fhzheng
 *
 */
public interface Performance {

	void perform();
}

Test部分的代码

	@Test
	public void aopTest() {
		AnnotationConfigApplicationContext context =
				new AnnotationConfigApplicationContext(AppConfig.class);
		Performance concert = context.getBean(Performance.class);
		concert.perform();
	}

测试结果

在这里插入图片描述

5 核心知识-切点表达式

切入点表达式
定义切入点的时候需要一个包含名字和任意参数的签名,还有一个切入点表达式,如execution(public * com.example.aop…(…))

切入点表达式的格式:execution([可见性]返回类型[声明类型].方法名(参数)[异常])
其中[]内的是可选的,其它的还支持通配符的使用:

  1. *:匹配所有字符
  2. …:一般用于匹配多个包,多个参数
  3. +:表示类及其子类
    4)运算符有:&&,||,!

切入点表达式关键词用例:
1)execution:用于匹配子表达式。
//匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意
@Pointcut(“execution(* com.cjm.model…(…))”)
public void before(){}

2)within:用于匹配连接点所在的Java类或者包。
//匹配Person类中的所有方法
@Pointcut(“within(com.cjm.model.Person)”)
public void before(){}
//匹配com.cjm包及其子包中所有类中的所有方法
@Pointcut(“within(com.cjm…*)”)
public void before(){}

3) this:用于向通知方法中传入代理对象的引用。
@Before(“before() && this(proxy)”)
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}

4)target:用于向通知方法中传入目标对象的引用。
@Before(“before() && target(target)
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}

5)args:用于将参数传入到通知方法中。
@Before(“before() && args(age,username)”)
public void beforeAdvide(JoinPoint point, int age, String username){
//处理逻辑
}

6)@within :用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。
@Pointcut(“@within(com.cjm.annotation.AdviceAnnotation)”)
- 所有被@AdviceAnnotation标注的类都将匹配
public void before(){}

7)@target :和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。
@Pointcut(“@target(com.cjm.annotation.AdviceAnnotation)”)
public void before(){}

8)@args :传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。
@Before(“@args(com.cjm.annotation.AdviceAnnotation)”)
public void beforeAdvide(JoinPoint point){
//处理逻辑
}

9)@annotation :匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。
@Pointcut(“@annotation(com.cjm.annotation.AdviceAnnotation)”)
public void before(){}

10)bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的。
@Pointcut(“bean(person)”)
public void before(){}

6 对目标对象和代理对象的理解,理解动态代理的实现方式

目标对象,一般都是指业务类下的方法
代理对象,它肯定是一个临时对象,是在运行时产生的一个对目标方法增强后的方法实现。由AOP自动生成。

动态代理的实现技术:
JDK动态代理
CGLib动态代理
所以,依赖的jar包一定有:

        <!-- 用于动态代理,基于类的代理 -->
        <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>2.1</version>
        </dependency>

1 com.sun.proxy. X X X X 2... XXXX 2 ... CGLiBXXXX

本质上,是原来业务类被代理成了新的增强后的类,然后用它的对象来做事情,站在用户角度来看,就好象是功能增加了。
其实,目标类和代理类是兄弟属层次关系,但一定有共同的父类接口,编程追求【面向接口编程】
这些动作由Spring容器来完成。

实质上,在具体实现时
如果是接口代理,默认为JDK代理,由JAVA自带功能来完成;
如果是类继承代理,由默认为CGLib代理,由第三方库来完成;
理解上,可以认为就是加了一个方法拦截器,在方法的前后添加了更多的动作,从而增强了方法。

因此
1 目标类和增强类均由Spring来管理,方便装配,注入,调用相应的对象
2 配置Aspect时,一定要注意:做什么,在哪里做,怎么做 之间的关系

特别注意

1 返回后通知和异常后通知,有个相应的返回结果,一个是返回值,一个是返回异常。

猜你喜欢

转载自blog.csdn.net/matrixbbs/article/details/89084446