什么是面向切面编程?
一个完整的程序,包括开始的启动日志,中间的业务逻辑实现,结尾的结束日志。
那么面向切面编程就是把业务逻辑实现作为一个切面,围绕这个切面编程。
AOP术语
- 通知(advice):定义了切面是什么以及何时使用。
·前置通知(Before):在目标方法被调用之前调用通知功能;
·后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
·返回通知(After-returning):在目标方法成功执行之后调用通知。
·异常通知(After-throwing):在目标方法抛出异常后调用通知。
·环绕通知 (Around):通知包裹了被通知的方法,在被通知的方法调用之前和 调用之后执行自定义方法
- 连接点(join point):是在应用执行过程中能够插入切面的一个点,例如:调用方法,抛出异常,修改字段等。
- 切点(Pointcut):通常使用明确的类和方法名称,或正则表达式匹配的类和方法名称。通知定义了切面的“什么”和“何时”的话,切点就定义了“何处”
- 切面(Aspect):通知和切点共同定义了切面的全部内容--他是什么,在何时和何处完成其功能。
- 引入(Introduction):允许向现有的类添加新方法或属性。
- 织入(Weaving):织入的三个时期:编译期,类加载期,运行期。
Spring对AOP的支持
Spring提供了4种类型的AOP支持:
- 基于代理的经典Spring AOP;
- 纯POJO切面;
- @AspectJ注解驱动的页面;
- 注入式AspectJ切面(适用于Spring各版本);
前三种都是Spring AOP的变种,Spring AOP构建在动态代理基础之上,因此,Spring对AOP的支持局限于方法拦截。
Spring AOP的配置繁琐,功能局限。所以推荐适用AspectJ来实现AOP功能。
下面展示@AspectJ注解驱动的页面的实现:
使用注解的方式:
package aop;
public interface IPerformance {
public void perform();
}
package aop;
import org.springframework.stereotype.Component;
@Component
public class Performance implements IPerformance{
@Override
public void perform() {
System.out.println("表演开始");
}
}
package aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
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.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class Audience {
@Pointcut("execution(* *.perform(..))")
public void perform() {}
@Before("perform()")
public void silenceCellPhone() {
System.out.println("Silencing Cell Phone");
}
@Before("perform()")
public void takeSeats() {
System.out.println("Taking Seats");
}
@After("perform()")
public void applause() {
System.out.println("CLAP CLAP CLAP");
}
@AfterThrowing("perform()")
public void demandRefund() {
System.out.println("Demanding a refund");
}
@Around("perform()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知开始");
pjp.proceed();
System.out.println("环绕通知结束");
}
}
package aop;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=aop.AOPConfig.class)
public class AopTest {
@Autowired
IPerformance perform;
@Test
public void test() {
perform.perform();
}
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext("aop");
IPerformance perfomance = (IPerformance) ac.getBean("performance");
perfomance.perform();
}
}
测试类写了2中实现测试的方法,选择其中一个就可以了。
使用XML实现的方式,如下:
package aop;
public interface IPerformance {
public void perform();
}
package aop;
public class Performance implements IPerformance{
@Override
public void perform() {
System.out.println("表演开始");
}
}
package aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class Audience {
public void silenceCellPhone() {
System.out.println("Silencing Cell Phone");
}
public void takeSeats() {
System.out.println("Taking Seats");
}
public void applause() {
System.out.println("CLAP CLAP CLAP");
}
public void demandRefund() {
System.out.println("Demanding a refund");
}
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知开始");
pjp.proceed();
System.out.println("环绕通知结束");
}
}
package aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AopXmlTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
IPerformance performance = (IPerformance) ac.getBean("performance");
performance.perform();
}
}
ApplicationContext.xml有2中配置AOP的方式如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/aop/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy/>
<bean id="audience" class="aop.Audience">
</bean>
<bean id="performance" class="aop.Performance">
</bean>
<context:component-scan base-package="aop"/>
<!-- more bean definitions go here -->
<aop:config>
<aop:aspect ref="audience">
<!-- <aop:pointcut id="performance" expression="execution(* *.perform(..))"/> -->
<aop:before pointcut="execution(* *.perform(..))"
method="silenceCellPhone"/>
<aop:before pointcut="execution(* *.perform(..))"
method="takeSeats"/>
<aop:after pointcut="execution(* *.perform(..))"
method="applause"/>
<aop:after-throwing pointcut="execution(* *.perform(..))"
method="demandRefund"/>
<aop:around pointcut="execution(* *.perform(..))"
method="around"/>
</aop:aspect>
</aop:config>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/aop/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy/>
<bean id="audience" class="aop.Audience">
</bean>
<bean id="performance" class="aop.Performance">
</bean>
<!-- <context:component-scan base-package="aop"/> -->
<!-- more bean definitions go here -->
<aop:config>
<aop:aspect ref="audience">
<!-- 注意这里的切点ID不要和上面的bean的ID相同,不然会引起下面引用的冲突报错 -->
<aop:pointcut id="perform" expression="execution(* *.perform(..))"/>
<aop:before pointcut-ref="perform" method="silenceCellPhone"/>
<aop:before pointcut-ref="perform" method="takeSeats"/>
<aop:after pointcut-ref="perform" method="applause"/>
<aop:after-throwing pointcut-ref="perform" method="demandRefund"/>
<aop:around pointcut-ref="perform" method="around"/>
</aop:aspect>
</aop:config>
</beans>
pom.xml 这里用的很多不用的类,根据个人需要删减
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.liangyu.aop</groupId>
<artifactId>aopDemo</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>aopDemo Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.4.RELEASE</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>aopDemo</finalName>
</build>
</project>
运行结果如下:
Silencing Cell Phone
Taking Seats
环绕通知开始
表演开始
环绕通知结束
CLAP CLAP CLAP