spring,springboot,AOP的简介,以及使用
AOP概述
- AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,
- 是对传统 OOP(Object-Oriented Programming,面向对象编程)的补充。
- AOP编程操作的主要对象是切面(aspect),而切面模块化横切关注点。
- 在传统的OOP编程中,更关注的是继承,继承属于一种自上而下纵向的操作,而面向切面,方法更趋向于横向的操作
AOP的一些概念,描述
切面(Aspect):封装横切关注点信息的类,每个关注点体现为一个通知方法。
通知(Advice):切面必须要完成的各个具体工作
目标(Target):被通知的对象
代理(Proxy):向目标对象应用通知之后创建的代理对象
连接点(Joinpoint):对应程序执行的某个特定位置。例如:类某个方法调用前、调用后、方法捕获到异常后等
切入点(pointcut):具体切入的或者扫描的类或者方法
要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为bean实例。
当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那些与 AspectJ切面相匹配的bean创建代理。
在AspectJ注解中,切面只是一个带有@Aspect注解的Java类,它往往要包含很多通知。
通知是标注有某种注解的简单的Java方法。
AspectJ支持5种类型的通知注解:
① @Before:前置通知,在方法执行之前执行
② @After:后置通知,在方法执行之后执行(无论方法正常结束还是异常结束,都会正常执行)
③ @AfterRunning:返回通知,在方法返回结果之后执行;
④ @AfterThrowing:异常通知,在方法抛出异常之后执行
⑥ @Around:环绕通知,围绕着方法执行;动态代理,手动推进目标方法运行(joinPoint.procced())
spring中注解使用
引入java包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
定义目标方法类
@Component
public class Calculator {
public int add(int i, int j) {
int result = i + j;
return result;
}
public int sub(int i, int j) {
int result = i - j;
return result;
}
public int mul(int i, int j) {
int result = i * j;
return result;
}
public int div(int i, int j) {
int result = i / j;
return result;
}
}
定义一个切面类:JoinPoint一定要出现在参数表的第一位
/**
* 日志切面
*/
@Component // 标识为一个组件
@Aspect // 标识为一个切面
public class LogAspect {
/**
* 声明切入点表达式
* @Pointcut("execution(* com.badger.spring.aop.*.*(..))")
* 第一个* : 任意修饰符 任意返回值
* 第二个* : 任意类
* 第三个* : 任意方法
* 参数列表..: 任意参数列表
*/
@Pointcut("execution(* com.badger.spring.aop.*.*(..))")
public void declarePointCut() {
}
/**
* 前置通知: 在目标方法(连接点)执行之前执行.
*/
@Before("execution(public int com.badger.spring.aop.Calculator.add(int,int))")
public void beforeMethod(JoinPoint joinPoint) {
// 获取方法的参数
Object[] args = joinPoint.getArgs();
// 方法的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("LogAspect==> The method " + methodName + " begin with " + Arrays.asList(args));
}
/**
* 后置通知: 在目标方法执行之后执行, 不管目标方法有没有抛出异常. 不能获取方法的结果
* 连接点对象: JoinPoint
*/
@After("declarePointCut()")
public void afterMethod(JoinPoint joinPoint) {
// 方法的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("LogAspect==> The method " + methodName + " ends .");
}
/**
* 返回通知: 在目标方法正常执行结束后执行. 可以获取到方法的返回值.
* 获取方法的返回值: 通过returning 来指定一个名字, 必须要与方法的一个形参名一致.
*/
@AfterReturning(value = "declarePointCut()", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result) {
// 方法的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("LogAspect==> The method " + methodName + " end with :" + result);
}
/**
* 异常通知: 在目标方法抛出异常后执行.
* 获取方法的异常: 通过throwing来指定一个名字, 必须要与方法的一个形参名一致.
* 可以通过形参中异常的类型 来设置抛出指定异常才会执行异常通知.
*/
@AfterThrowing(value = "declarePointCut()", throwing = "ex")
public void afterThrowingMethod(JoinPoint joinPoint, ArithmeticException ex) {
// 方法的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("LogAspect==> Thew method " + methodName + " occurs Exception: " + ex);
}
/**
* 环绕通知: 环绕着目标方法执行. 可以理解是 前置 后置 返回 异常 通知的结合体,更像是动态代理的整个过程.
*/
@Around("declarePointCut()")
public Object aroundMethod(ProceedingJoinPoint pjp) {
// 执行目标方法
try {
// 前置
Object result = pjp.proceed();
// 返回
return result;
} catch (Throwable e) {
// 异常通知
e.printStackTrace();
} finally {
// 后置
}
return null;
}
}
切面,可以直接在@Before("execution(public int com.badger.spring.aop.Calculator.add(int,int))")上加,也可以一直接定义一个单独的方法
/**
* 声明切入点表达式
* @Pointcut("execution(* com.badger.spring.aop.*.*(..))")
* 第一个* : 任意修饰符 任意返回值
* 第二个* : 任意类
* 第三个* : 任意方法
* 参数列表..: 任意参数列表
*/
@Pointcut("execution(* com.badger.spring.aop.*.*(..))")
public void declarePointCut() {
}
开起注解式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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<!-- 组件扫描 -->
<context:component-scan base-package="com.badger.spring.aop"></context:component-scan>
<!-- 基于注解使用AspectJ: 主要的作用是为切面中通知能作用到的目标类生成代理. -->
<aop:aspectj-autoproxy />
</beans>
spring aop在xml配置中使用
<!-- 目标对象 -->
<bean id="calculator" class="com.badger.spring.aop.Calculator"></bean>
<!-- 切面 -->
<bean id="logAspect" class="com.badger.spring.aop.LogAspect"></bean>
<!-- AOP: 切面 通知 切入点表达式 -->
<aop:config>
<!-- 切面 -->
<aop:aspect ref="logAspect">
<!-- 切入点表达式 -->
<aop:pointcut expression="execution(* com.badger.spring.aop.*.*(..))" id="myPointCut" />
<!-- 通知 -->
<aop:before method="beforeMethod" pointcut-ref="myPointCut" />
<aop:after method="afterMethod" pointcut-ref="myPointCut" />
<aop:after-returning method="afterReturningMethod" pointcut-ref="myPointCut" returning="result" />
<aop:after-throwing method="afterThrowingMethod" pointcut-ref="myPointCut" throwing="ex" />
<!-- <aop:around method="aroundMethod" pointcut-ref="myPointCut"/> -->
</aop:aspect>
</aop:config>
先把上述的切面对象com.badger.spring.aop.LogAspect,注解都去掉就可以了
springboot中的aop的使用
创建springboot项目,引用aop的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
剩下的步骤,定义目标类,切面类,就可以了,同上,spring中注解使用;只是不需要使用xml文件的形式,开启注解;而是在配置类中标注@EnableAspectJAutoProxy注解,开始aop
源码如下:org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.class
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
public static class CglibAutoProxyConfiguration {
}
}
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class }):先验证是否有这三个类
在上述,标注了@EnableAspectJAutoProxy后
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
会导入一个AspectJAutoProxyRegistrar.class,registry主要给spring容器,注入bean的实例的,后面的就不看了,感兴趣的,可以自己看
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
aop的使用,就到这里
上一篇: uniapp 仿瀑布流效果
下一篇: uniapp的tabBar组件