spring AOP(续)

AOP入门案例

导入jar包,并刷新

位置:在pom.xml文件的dependencies中

		<!--引入AOPjar包文件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

编辑配置类

@EnableAspectJAutoProxy:让aop有效

package com.jt.demo02.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.jt.demo02")
@EnableAspectJAutoProxy
public class SpringConfig {

}

编辑切面类

切面 = 切入点表达式 + 通知方法

*切入点表达式:为谁创建对象

*通知方法:对原有方法的扩建

@Aspect:标识当前类是一个切面

@Pointcut():标识切入点表达式

@Before():通知注解

package com.jt.demo02.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class TxAspect {
    //切入点表达式
    @Pointcut("bean(userServiceImpl)")
    public void  pointCut(){

    }
    //通知方法
    @Before("pointCut()")
    public void before(){
        System.out.println("AOP入门案例");
    }
}

编辑目标类

package com.jt.demo02.service;

public interface UserService {
    void addUser();
}
package com.jt.demo02.service;

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("新增用户成功");
    }
}

编辑测试类

package com.jt.demo02;

import com.jt.demo02.config.SpringConfig;
import com.jt.demo02.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestAspect {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
        //看上去是目标对象,实际是代理对象,已经被AOP封装
        UserService userService = context.getBean(UserService.class);
        System.out.println(userService.getClass());
        //代理机制:可以扩展方法
        userService.addUser();
    }
}

运行结果 

说明:有 $符号即为代理

详解切入点表达式

作用: 

配置AOP为谁创建代理对象

四种语法:

粗粒度语法:

语法一: bean(“对象的ID”) 只能匹配固定的类/对象 一个

@Pointcut("bean(userServiceImpl)")

 语法二: @Pointcut(“within(包名.类名)”)可以匹配多个类            *:表示通配

@Pointcut("within(com.jt.demo02.service.*)")
@Pointcut("within(com.jt.*.service.*)")

 说明: bean/within 都是粗粒度的匹配,匹配的是类(类中还有方法/方法可以重载!!!)

细粒度语法:

语法三: @Pointcut(“execution(返回值类型 包名.类名.方法名(参数列表))”)

@Pointcut("execution(void com.jt.demo02.service.UserServiceImpl.addUser())")

匹配任意返回值类型,service包下的所有的类,任意方法,任意参数

@Pointcut("execution(* com.jt.demo02.service..*.*(..))")

语法四:@Pointcut("@annotation(自定义注解)")

步骤一:自定义注解

package com.jt.demo2.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) //注解对方法有效
@Retention(RetentionPolicy.RUNTIME) //运行期有效
public @interface TX {
    
}

 步骤二:使用注解

在这里插入图片描述

 步骤三:配置AOP切面

@Pointcut("@annotation(com.jt.demo02.anno.Tx)")
    public void  pointCut(){

    }

详解通知方法

作用: 当用户满足了切入点表达式,则才会执行扩展方法.
注意事项: 通知必须与切入点表达式绑定!!!

通知方法:

前置通知:@Before

作用一:在目标方法运行前执行.

    @Before("pointCut()")
    public void before(){
        System.out.println("AOP入门案例");
    }

后置通知:@AfterReturning

作用一:在目标方法执行之后执行

    @AfterReturning("pointCut()")
    public void AfterReturning(){
        System.out.println("AOP后置通知");
    }

 作用二:动态获取返回值

 /**
     *  记录目标方法的返回值结果
     *  returning: 后置通知获取返回值的属性
     */
    @AfterReturning(value = "pointCut()",returning = "result")
    public void afterReturning(Object result){
        System.out.println("方法的返回值:"+result);
    }

异常通知:@AfterThrowing

作用一:目标方法执行时,抛出异常时,异常通知执行

    @AfterThrowing("pointCut()")
    public void AfterThrowing(){
        System.out.println("AOP异常通知");
    }

作用二:获取异常信息

 /**
     * 说明: 如果程序执行抛出异常,则可以由异常通知进行记录
     *      throwing:抛出异常的属性
     */
    @AfterThrowing(value = "pointCut()",throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint,Exception exception){
        //exception.printStackTrace();
        System.out.println("异常信息"+exception.getMessage());
    }

最终通知:@After不管目标方法执行是否正确,都要执行. 一般不用

 @After("pointCut()")
    public void after(){
        System.out.println("我是最终通知!!");
    }

***环绕通知

说明:
1. 前四大通知类型不能控制目标方法的运行,所以在使用时一般记录程序的运行状态.
2. 在目标方法执行前后都要运行, 只有环绕通知才可以控制目标方法是否运行. 使用最多的通知方法.

 /**
     * 注意事项: 环绕通知中必须添加参数,并且必须位于第一位
     * 用法:
     *  Proceed with the next advice or target method invocation
     *  1.如果有下一个通知,则执行下一个通知,
     *  2.如果没有下一个通知则执行目标方法
     * @return
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知开始");
        Object result = joinPoint.proceed();
        System.out.println("环绕通知结束");
        return result;
    }

连接点joinPoint的用法

概念:

当用户调用方法时,如果该方法被切入点表达式匹配.则Spring会为其对象创建代理.则将这个方法称之为连接点

作用:

通过JoinPoint对象可以获取当前方法的所有的参数,可以供用户进行记录

代码实现:

 //通知方法: 对原有方法的扩展
    @Before("pointCut()")
    public void before(JoinPoint joinPoint){
        //1.获取目标对象的类型
        Class targetClass = joinPoint.getTarget().getClass();
        //2.获取目标对象名称
        String targetName = joinPoint.getSignature().getDeclaringTypeName();
        //3.获取目标方法的名称
        String methodName = joinPoint.getSignature().getName();
        //4.获取参数数据
        Object[] args = joinPoint.getArgs();
        System.out.println("目标对象类型:"+targetClass);
        System.out.println("目标对象名称:"+targetName);
        System.out.println("目标方法名称:"+methodName);
        System.out.println("参数名称:"+ Arrays.toString(args));
    }

JoinPoint和ProceedingJoinPoint区别

1.ProceedingJoinPoint只适用于环绕通知,因为只有环绕通知,才能控制目标方法的运行.

2.JoinPoint 适用于其它的四大通知类型,可以用来记录运行的数据.

3. ProceedingJoinPoint 中有特殊的方法proceed();

4. 如果使用"JoinPoint" 则必须位于参数的第一位

切面顺序

在这里插入图片描述

在这里插入图片描述

 控制AOP执行顺序: Order注解
在这里插入图片描述

 Spring中默认代理策略 

如果目标对象有接口, 则默认采用JDK动态代理模式,
如果目标对象没有接口, 则默认采用CGLIB代理方式.

代理模式的修改

如果需要改变默认的模式,则只能强制使用cglib代理模式.

在这里插入图片描述

注解:

@Aspect:标识当前类是一个切面

@EnableAspectJAutoProxy:让@Aspect有效

@Pointcut:标识切入点表达式

@Before:前置通知

@AfterReturning:后置通知

@AfterThrowing:异常通知

@After:最终通知

 @Around:环绕通知

@Order:控制AOP执行顺序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值