spring的aop

aop

aop,面向切面编程。面向对象编程时对一个对象进行抽象。而面向切面编程时对不同的事物进行抽象,例如将不同的类中的方法都统一提出来,集中对这些方法进行操作。

aop实现原理

aop的底层是通过一个BeanDefinition注册一个AspectJAwareAdvisorAutoProxyCreator的bean,这个bean是个BeanPostProcess后处理器,而就是这个后处理器内部会调用aop封装的动态代理方法,底层有两个方法,分别是JDK和Cglib。
而注解方法和XML配置方式的底层都是相同,就是进入底层代码是调用的接口不同。

aop的基本概念

名词 解释
Target(目标对象) 被增强的方法的对象
Proxy( 代理对象) 对目标对象进行增强后的对象
Joinpoint(连接点) 目标对象中可以被增强的方法
Pointcut(切入点) 目标对象中实际被增强的方法
Advice(通知\增强) 增强部分的代码逻辑
Aspect(切面) 增强和切入点的结合
Weaving(织入) 将通知和切入点动态结合的过程

aop的五种通知

通知名称 执行时机
前置通知 目标方法执行之前执行
后置通知 目标方法执行之后执行,当方法异常时,不执行
环绕通知 目标方法前后执行,方法异常时,后环绕方法不执行
异常通知 目标方法抛出异常时执行
最终通知 目标方法无论是否有异常,最后都会执行

aop的切点表达式的配置

aop的两种切面配置方式

execution([访问修饰符] 返回的类型 包名.类名.方法名(参数))

当然在配置表达式时可以使用通配符

// .. 表示任意的参数
execution([访问修饰符] 返回的类型 包名.类名.方法名(..))


// * 表示任意类或方法
execution([访问修饰符] 返回的类型 包名.*.*(..))

// 包名和类名之间使用双点表示该包极其子包下的类
execution([访问修饰符] 返回的类型 包名..*.*(..))

aspect进行配置

xml标签配置

<aop:config>
        
        <aop:pointcut id="myPointcut" expression="execution(void com.service.impl.UserServiceImpl.show1())"/>
        <aop:pointcut id="myPointcut3" expression="execution(void com.service.impl.UserServiceImpl.show2())"/>
        <aop:pointcut id="myPointcut4" expression="execution(void com.service.impl.UserServiceImpl.show3())"/>
        
        <aop:pointcut id="myPointcut2" expression="execution(void com.service.impl.*.*(..))"/>
        
        
        <aop:aspect ref="myAdvice">
            
            <aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
            
            <aop:after method="afterReturningAdvice" pointcut-ref="myPointcut"/>
            
            <aop:after-returning method="afterAdvice" pointcut-ref="myPointcut" />
            
            <aop:around method="around" pointcut-ref="myPointcut"/>
            
            <aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="myPointcut"/>
        aop:aspect>
    aop:config>

通知类配置

public class MyAdvice {

    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("当前对象是:"+joinPoint.getTarget());
        System.out.println("当前对象的表达式:"+joinPoint.getStaticPart());
        System.out.println("前置方法.....");
    }

    public void afterAdvice(){
        System.out.println("最终方法.....");
    }

    public void afterReturningAdvice(){
        System.out.println("后置方法.....");
    }

    public Object around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("前置环绕方法执行.....");
            Object proceed = joinPoint.proceed();
            System.out.println("后置环绕方法执行.....");
            return proceed;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    public void afterThrowing(Throwable e){
        System.out.println("当前的异常的信息为:"+e);
    }

}

当然这里的方法名只要一一对应就行,实际上想取什么名字都可以,但是一般还是取一些固定的名字,方便说明。

advisor配置

Xml配置

<aop:config>
        
        <aop:pointcut id="myPointcut" expression="execution(void com.service.impl.UserServiceImpl.show1())"/>
        <aop:pointcut id="myPointcut3" expression="execution(void com.service.impl.UserServiceImpl.show2())"/>
        <aop:pointcut id="myPointcut4" expression="execution(void com.service.impl.UserServiceImpl.show3())"/>
        
        <aop:pointcut id="myPointcut2" expression="execution(void com.service.impl.*.*(..))"/>

        
        <aop:advisor advice-ref="myAdvice2" pointcut-ref="myPointcut3"/>
        <aop:advisor advice-ref="myAdvice3" pointcut-ref="myPointcut4"/>
    aop:config>

通知类配置

public class MyAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {


    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("接口实现的后置方法");
    }

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("接口实现的后置方法");
    }
}
public class MyAdvice3 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        System.out.println("接口环绕前置方法执行");
        Object result = methodInvocation.getMethod().invoke(methodInvocation.getThis(), methodInvocation.getArguments());
        System.out.println("接口环绕后置方法执行");
        return result;
    }
}

这中方式需要我们的通知类实现对应的接口,之后重写我们的接口方法。于是,在XML配置中就不需要指定我们的方法了。

Aop注解方式

要想使用注解,我们需要在我们的XML配置配置一下标签


    <aop:aspectj-autoproxy/>

如果使用的的时配置类的话,需要加上@EnableAspectJAutoProxy标签

@Configuration
@ComponentScan("com")
@EnableAspectJAutoProxy
public class SpringConfig {
}

之后只需要在我们的通知类中加一个@Aspect标签,为每一个标签配置一下方法标签就可以了。

@Component
@Aspect
public class MyAdvice {


//配置切点
    @Pointcut("execution(void com.service.impl.UserServiceImpl.show2())")
    public void pointcut(){}


    @Before("MyAdvice.pointcut()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("当前对象是:"+joinPoint.getTarget());
        System.out.println("当前对象的表达式:"+joinPoint.getStaticPart());
        System.out.println("前置方法.....");
    }

    @AfterReturning("MyAdvice.pointcut()")
    public void afterAdvice(){
        System.out.println("最终方法.....");
    }


    @After("MyAdvice.pointcut()")
    public void afterReturningAdvice(){
        System.out.println("后置方法.....");
    }

    @Around("MyAdvice.pointcut()")
    public Object around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("前置环绕方法执行.....");
            Object proceed = joinPoint.proceed();
            System.out.println("后置环绕方法执行.....");
            return proceed;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    @AfterThrowing(pointcut = "MyAdvice.pointcut()",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("当前的异常的信息为:"+e);
    }

}

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