1、AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充
2、AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点
3、在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里
4、AOP 的好处:
①每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
②业务模块更简洁, 只包含核心业务代码
5、AOP术语:
①切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
②通知(Advice): 切面必须要完成的工作,即:标注有某种注解的简单的 Java 方法
③目标(Target): 被通知的对象
④代理(Proxy): 向目标对象应用通知之后创建的对象
⑤连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。
⑥切点(pointcut):每个类都拥有多个连接点,即AOP的扫描规则。例如 处理逻辑类的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件
6、在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP(AspectJ比Spring原生的AOP注解好用)
7、基于注解方式配置AOP通知
(1)使用Aspectj来配置Spring的AOP环境,Spring自己也有AOP框架,不过Aspectj好一点
(2)需要的jar包:aspectjrt.jar、aspectjtools.jar、aspectjweaver.jar、org.aspectj.matcher.jar
(3)基于注解的方式配置aop
①配置文件中加入aop命名空间,即:在spring配置文件的命名空间里面勾选aop
②配置文件中添加<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
③把横切关注点代码“beforeMethod()”抽象到切面类“LoggingAspect”中
④把切面类使用@Component加入IOC容器中
⑤切面内需要加入@Aspect注解
⑥在类中声明通知,即:在方法前加入(一个关注点可声明多个注解)
①前置通知(方法执行前执行):@Before
②后置通知(方法执行后执行):@After
③返回通知(方法返回后执行):@AfterRunning、
④异常通知(抛出异常后执行):@AfterThrowing
⑤环绕通知(围绕着方法执行):@Around
⑦为注解添加切入点表达式
⑧在关注点方法的属性加入JoinPoint函数,用于获取相关值
(4)AspectJ使用步骤:
① 添加AspectJ 类库(jar包)
② 将 aop Schema 添加到<beans>
根元素中
③ 在 Spring IOC 容器中启用 AspectJ 注解支持,即配置文件<beans>
中添加<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
④ 使用AOP的类(切面)的类名前面配置@Aspect
(5)AspectJ 支持 5 种类型的通知注解:
① @Before
: 前置通知, 在方法执行之前执行
② @After
: 后置通知, 在方法执行之后执行
③ @AfterRunning
: 返回通知, 在方法返回结果之后执行
④ @AfterThrowing
: 异常通知, 在方法抛出异常之后
⑤ @Around
: 环绕通知, 围绕着方法执行
8、文件
①TestMain.java:测试类
②AOPoperations.java:方法接口
③AOPopeartionsImpl.java:实现接口和接口方法的类
④LoggingAspect.java:优先级较低的切面类
⑤LoggingAspect2.java:优先级较高的切面类
⑥PointCut.java:存放代表可重用的切点表达式的方法的类
⑦annotationNotificationContext.xml:配置方法
9、TestMain.java
package com.demo.sshtest.aop2.annotationNotification;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain {
public static void main(String[] args) {
//创建spring的IOC容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotationNotificationContext.xml");
//从IOC容器中获取bean实例(这里获取的是接口类的实例,而不是实现接口的类的实例)
AOPoperations aoPopeartions = (AOPoperations)applicationContext.getBean(AOPoperations.class);
//使用bean
String result = aoPopeartions.addA("strsdlkfadkljklj");
System.out.println("-------------");
String result2 = aoPopeartions.addB("weefweewf");
System.out.println("-------------");
try {
String result3 = aoPopeartions.addCal("1","2a");
} catch (Exception e) {
}
}
}
10、AOPoperations.java
package com.demo.sshtest.aop2.annotationNotification;
public interface AOPoperations {
public String addA(String str);
public String addB(String str);
public String addCal(String str1,String str2) throws Exception;
}
11、AOPopeartionsImpl.java
package com.demo.sshtest.aop2.annotationNotification;
import org.springframework.stereotype.Component;
@Component
public class AOPopeartionsImpl implements AOPoperations{
public String addA(String str) {
String result = str+"_AAAAAAAAAA";
return result;
}
public String addB(String str) {
String result = str+"_BBBBBBBBBB";
return result;
}
public String addCal(String str1, String str2) throws Exception{
String result = "";
result = "" + (Double.parseDouble(str1) + Double.parseDouble(str2));
return result;
}
}
12、LoggingAspect.java
package com.demo.sshtest.aop2.annotationNotification;
import java.util.Arrays;
import java.util.List;
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;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
//把LoggingAspect类声明为切面
/*
1、把该类放入IOC容器
2、用@Aspect声明切面
*/
@Order(2)
@Aspect
@Component
public class LoggingAspect {
/*
切入点表达式写法:"execution(控制权限 包名.类名.方法名(参数类型))"
例如:@Before(public com.demo.sshtest.aop2.annotationNotification.AOPoperations.addC(String,String))
其中,控制权限、类名、方法名、参数类型可以用"*"代替,如:(* com.demo.sshtest.aop2.annotationNotification.*.*(*,*))
另外,参数类型还可以用".."代表任意类型和任意数量的参数参数类型
*/
//声明前置通知:在目标方法开始之前执行
@Before("com.demo.sshtest.aop2.annotationNotification.PointCut.pointcutexpression()")
public void beforeMethod(JoinPoint joinPoint){
//通过在@Before标注的方法的参数中添加JoinPoint来获取当前调用的方法名及其传入的值
//获取方法名 :joinPoint.getSignature().getName()
//获取传入方法的值 :joinPoint.getArgs()
String methodname = joinPoint.getSignature().getName();
List<Object> values = Arrays.asList(joinPoint.getArgs());
System.out.println("Begin run method "+methodname+" and the value is:"+values);
}
//声明后置通知:在目标方法执行之后执行,无论是否发生异常
//后置通知不能获取方法返回的值
@After("com.demo.sshtest.aop2.annotationNotification.PointCut.pointcutexpression()")
public void afterMethod(JoinPoint joinPoint){
//通过在@After标注的方法的参数中添加JoinPoint来获取当前调用的方法名及其传入的值
//获取方法名 :joinPoint.getSignature().getName()
//获取传入方法的值 :joinPoint.getArgs()
String methodname = joinPoint.getSignature().getName();
List<Object> values = Arrays.asList(joinPoint.getArgs());
System.out.println("End run method "+methodname+" and the value is:"+values);
}
//声明返回通知:在目标方法返回结果之后执行
@AfterReturning(value="com.demo.sshtest.aop2.annotationNotification.PointCut.pointcutexpression()",returning="result")
public void afterReturnMethod(JoinPoint joinPoint,Object result){
//通过在@AfterReturning标注的方法的参数中添加JoinPoint来获取当前调用的方法名及其返回的值
//获取方法名 :joinPoint.getSignature().getName()
//获取传入方法的值 :joinPoint.getArgs()
String methodname = joinPoint.getSignature().getName();
System.out.println("run method "+methodname+" and Return:"+result);
}
//声明异常返通知:在目标方法抛出异常之后执行
//可以访问异常对象,且指定出现指定异常的执行通知代码,即afterThrowing()中的Exception
//配置中@AfterThrowing的throwing值要和afterThrowing中Exception的参数名一致
//如果想要只在@AfterThrowing中输出定制的异常信息,则需要在对应方法里面直接使用throw来抛出异常,而不是用try catch,因为catch会完成完整的异常捕获,异常捕获完成后@AfterThrowing不会运行
@AfterThrowing(value="com.demo.sshtest.aop2.annotationNotification.PointCut.pointcutexpression()",throwing="exception")
public void afterThrowingMethod(JoinPoint joinPoint,Exception exception){
String methodname = joinPoint.getSignature().getName();
System.out.println(methodname+" throw an exception:"+exception.getMessage());
}
//声明环绕通知:在前置通知执行前后运行,后置通知前执行,在异常通知执行后,则不执行
//环绕通知需要携带ProceedingJoinPoint类型的参数
//环绕通知类似于动态代理全过程:ProceedingJoinPoint可以决定是否执行目标方法
//环绕通知必须有返回值,返回值为目标方法返回值
@Around("com.demo.sshtest.aop2.annotationNotification.PointCut.pointcutexpression()")
public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){
Object result = null;
try{
String methodname = proceedingJoinPoint.getSignature().getName();
System.out.println(methodname+" aroundMethod...before note....");
result = proceedingJoinPoint.proceed();
System.out.println(methodname+" aroundMethod...after note...."+result);
}catch(Throwable e){
throw new RuntimeException();
}
return result;
}
}
13、LoggingAspect2.java
package com.demo.sshtest.aop2.annotationNotification;
import java.util.Arrays;
import java.util.List;
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;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
//关于切点优先级,可以使用@Order()来设定,括号中的数值越小,优先级越高
@Order(1)
@Aspect
@Component
public class LoggingAspect2 {
//声明前置通知:在目标方法开始之前执行
@Before("com.demo.sshtest.aop2.annotationNotification.PointCut.pointcutexpression()")
public void beforeMethod2(JoinPoint joinPoint){
String methodname = joinPoint.getSignature().getName();
List<Object> values = Arrays.asList(joinPoint.getArgs());
System.out.println("LoggingAspect2-->Begin run method "+methodname+" and the value is:"+values);
}
//声明后置通知:在目标方法执行之后执行,无论是否发生异常
@After("com.demo.sshtest.aop2.annotationNotification.PointCut.pointcutexpression()")
public void afterMethod2(JoinPoint joinPoint){
String methodname = joinPoint.getSignature().getName();
List<Object> values = Arrays.asList(joinPoint.getArgs());
System.out.println("LoggingAspect2-->End run method "+methodname+" and the value is:"+values);
}
}
14、PointCut.java
package com.demo.sshtest.aop2.annotationNotification;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
public class PointCut {
//关于可重用的切点表达式
//1、先创建一个void类型的空方法,方法名任意,不需要写任何参数和代码
//2、为步骤一中的方法添加@Pointcut()注解
//3、把需要重用的切点表达式写到@Pointcut()中
//4、调用时,在需要调用的注解标签内写上该方法的包名+类名+方法名,如果跟该方法在同一个包类,则可以省略包名,如果在同一个类里面,则可以省略包名和类名
//调用方法例子:@Before("com.demo.sshtest.aop2.frontnotification.PointCut.pointcutexpression()")
@Pointcut("execution(* com.demo.sshtest.aop2.annotationNotification.AOPoperations.*(..))")
public void pointcutexpression(){}
}
15、annotationNotificationContext.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"
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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<context:component-scan base-package="com.demo.sshtest.aop2.annotationNotification"></context:component-scan>
<!-- 使AspjectJ注解起作用:自动为匹配的类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
16、注意事项:
①实现接口的类需要使用@Component、@Controller、@Respository、@Service标签注释
②配置文件中要配置扫描所有需要的类
③设置切点优先级,可以使用@Order()来设定,括号中的数值越小,优先级越高
④切点类不仅需要使用@Aspect注释还要使用@Component、@Controller、@Respository、@Service标签注释
⑤在@Before、@After、@AfterRunning、@AfterThrowing、@Around的括号里面能直接配置切点表达式或者存着切点表达式的类的方法
⑥切点表达式格式为:execution(类修饰类型.包名.类名.方法名(..)),其中方法名后面括号的“..”代表省略方法参数
⑦从IOC容器中获取bean实例(获取的是接口类的实例,而不是实现接口的类的实例)
17、项目目录(只看com.demo.sshtest.apo2.annotationNotification和annotationNotification.xml)
18、demo
https://download.csdn.net/download/qq_22778717/10476407