Spring AOP的理解以及项目应用

字节一面关于Spring AOP的问题让我对Spring AOP有了深入了解的想法,现在来整理一下对Spring AOP的理解

class A{
	@Logxxx
	public void methodA(){
		methodB();
	}
	
	@Logxxx
	public void methodB(){
	}
}

问题:
A类中有两个方法 methodA和methodB,方法是都有自定义注解@Logxxx,@Logxxx的作用是在方法执行之后输出一段日志,如果执行了方法methodA会输出几次日志信息?
结论:
只有方法methodA执行之后输出一段log日志。
原因:
因为调用方法methodA的时候,因为加了@Logxxx日志,spring aop会生成代理对象,但是在执行methodB方法的时候使用的对象不是代理对象,所以不会进行增强。

我的理解:
对aop的理解:
1.什么是aop: 面向切面编程,通过预编译或者运行时动态编译实现程序功能增强的一种技术。
2. aop可以拦截指定的方法并对方法进行增强,不需要在代码中加入需求代码,使业务代码与非业务代码分离。
3. AOP 采取横向抽取机制(动态代理),取代了传统纵向继承机制的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。
4. 通俗的说就是在代码执行前后进行某些处理比如日志、权限校验等
aop术语:

	对象术语:描述aop中各个对象的部分
			连接点(Join Point):所有符合条件的切点的集合,可能有一个或者多个我们成为连接点。
			切入点/切点(Pointcut):切点是指通知(Advice)所要织入(Weaving)的具体位置,满足我们条件的目标方法。
			比如使用自定义注解,切点就是这个注解所标志的地方。比如我们指定规则,以find开头的才执行我们自定义通	知,那么这些满足条件的以find开头的方法就是切点。
			切面 (Aspect):切点和通知的组合叫法。连接点是我们没有定义那个find开头规则时,满足条件的全部的方法。
			通知/增强(Advice):我们编写的希望在aop时执行的方法,通常希望在目标方法前后执行。
				五种通知:
					前置通知(Before):在目标方法被调用前执行的行为。
					后置通知(After):在目标方法执行完成后执行的行为,不能获取到方法的输出。
					后置返回通知(After-returning):在目标方法成功执行后执行的行为,可以获取到方法的输出。
					后置异常通知(After-throwing):在目标方法抛出异常后执行的行为。
					环绕通知(Around):包裹了目标方法,可以在其执行前后执行自定义的行为。
		行为术语:aop实现过程中涉及的具体行为
			引入(Introduction):向现有类中添加新的方法和属性,我们可以把切面的属性引入到目标类。
			织入(Weaving):织入指的是将切面应用到目标对象,在这个过程中会生成新的代理对象。
				织入三种时期
					 编译期:在目标类被编译时进行织入,需要依赖于特殊的编译器。AspectJ 的织入编译器就采用的这种方式。
					 类加载期:在目标类被加载到 JVM 时进行织入,需要依赖于特殊的类加载器。这种方式会在目标类被引入应用前增强目标类的字节码。
					 运行期:在应用运行的某一具体时刻进行织入。在这种情况下,AOP 容器会为目标对象动态地创建一个代理对象,Spring AOP 就采用的这种方式。
		具体例子理解:
				被增强的方法:王老师的语文课
				目标方法所在类:王老师
				通知(前置通知):做某事前擦黑板,重点是擦黑板这一行为
				连接点:老师上课前的时间,并不确定是哪些老师上哪门课前
				切点:王老师上语文课前这一时间点
				切面:在王老师上语文课前擦黑板

Spring AOP的实现机制
spring 是通过动态代理和动态字节码实现AOP的。
动态代理:JDK动态代理和CGLIB动态代理。

	1. JDK动态代理:Spring AOP的首选方法,当目标对象实现一个接口时可以使用JDK动态代理。
	2. CGLIB代理:目标对象如果没有实现接口,可以使用CGLIB代理,原理是继承实现的所以不能代理final,static修饰的目标类,并且方法不能用private修饰。

我在项目中的应用-自定义log注解

//自定义注解
@Retention(RetentionPolicy.RUNTIME) //该注解用来修饰注解的生命周期
@Target(value = {ElementType.METHOD})// 表示该注解的作用范围
@Documented //有该注解的注解生成javadoc的时候是否会被记录
public @interface Log{
    int level() default 2;
}
//定义切面 
@Component
@Aspect
@RequiredArgsConstructor
@Slf4j
public class LogAspect {
 	//切点
    @Pointcut("@annotation(com.xx.xx.xx.Log)")
    public void printLog(){

    }
 
    /**
     * 输出日志
     * @param joinPoint
     */
    @After(value = "printLog()")
    public void doAfterPrintLog(JoinPoint joinPoint){
        //获取参数
        Object[] args = joinPoint.getArgs();
        // 获取方法名
        String methodName = joinPoint.getSignature().getName();
        // 反射获取目标类
        Class<?> targetClass = joinPoint.getTarget().getClass();
        // 拿到方法对应的参数类型
        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        // 根据类、方法、参数类型(重载)获取到方法的具体信息
        Method objMethod = null;
        try {
            objMethod = targetClass.getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        // 拿到方法定义的注解信息
        PreAuthCheck annotation = objMethod.getDeclaredAnnotation(Log.class);
        System.out.println("日志级别:"annotation.level());
    }

}

你可能感兴趣的:(Spring,AOP,spring,java,后端)