AOP 知识

133 阅读4分钟

1.切入点表达式

1.1bean表达式

说明:根据dean的ID拦截指定的对象

 @Pointcut("bean(userServiceImpl)")
    public void pointcut(){

    }

1.2within表达式

说明:按照类型匹配,可以使用通配符*号

语法:        

                
1. @Pointcut("within(com.jt.service. UserServicelmpl) ")
                        //只拦截UserServicelml的类
                
2. @Pointcut( "within(com.jt.service. *)")
                        //拦截com.it.service下的一级的类.

3. @Pointcut( "within(com.jt.service.. *)")
                        //拦截 com.jt.service下的所有类
                
4. @Pointcut ( "within(com. * . service..*)")
                        //拦截com.任意包.service下所有包下的所有类

说明:上述的2种操作方法  粒度较粗,一般情况下不用

1.3execution表达式

作用:粒度比较细,可以按照方法参数进行匹配

语法:

语法:  @Pointcut("execution(返回值类型 包名.类名.方法名(参数列表))")
1. 按照类型方法匹配
@Pointcut("execution(* com.jt.service.UserServiceImpl.addUser())")
2. 要求返回值任意, com.jt.service包下的所有的子孙类中的任意方法的任意参数要求拦截.
@Pointcut("execution(* com.jt.service..*.*(..))")

3. 要求返回值任意, com.jt.service包下的所有的子孙类中的add开头的方法并且参数1个是int类型 进行拦截
@Pointcut("execution(* com.jt.service..*.add*(int))")

1.4@annotation表达式

作用:可以根据用户的自定义注解拦截

1.4.1完成自定义注解Lyj

package com.jt.anno;

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

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

1.4.2标记注解

 1.4.3AOP拦截注解

2.关于通知的讲解

2.1关于AOP通知的用法

第一类:

1.@Before("pointcut()")

2.@AfterReturning( "pointcut()")

3.@AfterThrowing("pointcut()")

4.@After("pointcut()")

可以记录程序的执行的各个过程 为日志提供记录

第二类:

5.@around环绕通知  可以控制目标方法是否执行。环绕通知可以控制业务流转的过程!!!

 例子:

1.权限的校验

2.缓存系统 

3.异常的处理等                                                                                                                                 

2.1.1通知中常用的API

需求:\

  1. 获取当前的目标对象的类型.\
  2. 获取当前的方法名称\
  3. 获取当前传递的参数.

常见报错: ProceedingJoinPoint is only supported for around advice ProceedingJoinPoint 只能用到环绕通知中.

//1.前置通知: 在目标方法执行之前执行.
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){//连接点:获取方法中的数据
        Class targetClass = joinPoint.getTarget().getClass();
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getSignature().getDeclaringTypeName();
        Object[] objs = joinPoint.getArgs();
        System.out.println("我是前置通知!!!!");
        System.out.println("类型:"+ targetClass);
        System.out.println("方法名称:"+methodName);
        System.out.println("类的名称:"+className);
        System.out.println("方法中携带的参数:"+ Arrays.toString(objs));
    }

 2.1.2后置通知用法

需求: 记录一下用户目标方法的返回值
说明: 通过属性returning 获取方法的返回值

 //2.后置通知: 在目标方法执行之后执行
    // 通过returning = "result"属性,获取目标方法的返回值,当作参数传递给result
    @AfterReturning(value = "pointcut()",returning = "result")
    public void afterReturn(Object result){
        System.out.println("我是后置通知!!!!");
        System.out.println("用户的返回值为:"+result);
    }

2.1.3异常通知用法

说明: 如果用户执行业务方法时,报错了,则可以使用异常通知记录日志.
用法:

//3.异常通知: 目标方法执行报错时,执行该通知
    @AfterThrowing(value = "pointcut()",throwing = "exception")
    public void afterThrowing(Exception exception){
        System.out.println("我是异常通知!!!!");
        System.out.println("获取异常信息:"+exception.getMessage());
        exception.printStackTrace();
    }

 2.2切面排序

说明:根据@Order注解  实现切面的排序

2.2.1编辑SpringAOP

 //5.重点掌握 环绕通知: 在目标方法执行前后都要执行. 控制目标方法
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知A执行前!!!!");
        //底层调用动态代理的invoke方法,执行目标方法
        Object result = joinPoint.proceed();
        System.out.println("环绕通知A执行后!!!!");
        return result;
    }

2.2.2编辑SpringAOP2

package com.jt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component  //将类交给spring容器管理
@Aspect     //标识切面类
@Order(1)   //AOP第一个执行  数字越小越靠前
public class SpringAOP2 {

    //通过环绕通知 指定切入点表达式.
    @Around("@annotation(com.jt.anno.Lyj)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //1.如果有下一个通知,则执行通知方法,没有通知,则执行目标方法
        System.out.println("执行环绕通知B开始");
        Object result = joinPoint.proceed();
        System.out.println("执行环绕通知B结束");
        return result;
    }
}

2.3关于对象生成策略说明

默认策略:

 1.Spring中默认的采用的动态代理的规则是JDK代理,如果被代理者没有接口,则自动使用CGLIB

 2.如果需要修改为cglib代理,则添加如下代码

@Configuration
@ComponentScan("com.jt") //包扫描
@EnableAspectJAutoProxy(proxyTargetClass = true)  //开启AOP
public class SpringConfig {


}

SpringBoot中默认代理模式采用CGLIB代理,如果需要修改为JDK代理则需要修改配置文件即可

3.关于Spring总结

1.为什么学习spring框架 让程序设计实现松耦合.
2.什么是面向接口编程 以后对象中的属性一般写接口. java中多态的体现. 属性类型更加的灵活         松耦合.
3.什么是IOC Ioc全称Inversion of Control,即“控制反转”,这是一种设计思想。对象创建的权利由     Spring框架完成.由容器管理对象的生命周期.
4.Spring容器启动方式 1. xml方式 2.注解方式
5.什么时候使用工厂模式: 1.对象不能直接实例化的时候. 2.spring框架整合其它第三方框架时使用.         FactoryBean
6.单例多例问题: 默认条件下是单例模式 @Scope(“prototype”)
7.懒加载规则: 1. 默认条件下 懒加载无效 添加注解@Lazy 有效. 只对单例模式有效.
8.spring生命周期管理 4个过程: 1.对象创建 2. 对象初始化 @PostConstruct 3. 业务调用 4.对象销          毁 @PreDestroy
9.Spring中依赖注入的注解@Autowired 1.默认按照类型注入 2.可以按照名称注入 @Qualifier(“cat”)         @Resource java中的注解.
10.MVC 设计思想 View 视图层 Model业务层 Control 控制层
10.根据MVC设计思想: 层级代码结构 Controller/Service/Mapper|Dao
11.@Value spring为属性动态赋值 基本类型和String和集合(几乎不用)
12.动态代理 JDK动态代理/CGLib动态代理
13.AOP 面向切面编程 在不改变源码的条件下对方法进行扩展.
14.AOP常见注解
1. @Aspect 标识切面
2. @Pointcut 标识切入点表达式 4种写法 2种常用
3. 五个通知注解
4. @EnableAspectJAutoProxy(proxyTargetClass = true) //开启AOP
5. 排序注解 @Order