Java_Spring第三天笔记(AOP)

今日内容

  1. IOC原理
  2. AOP
    1. AOP概述以及相关的术语
    2. AOP使用
    3. AOP相关的配置
  3. 基于注解的AOP

1,IOC原理

1.1 组件扫描过滤器(掌握)

  • xml版(重点掌握)

    <!--包扫描-->
    <context:component-scan base-package="com.itheima">
        <!--
    		不扫描@Controller注解
    	-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
  • 注解版

    @ComponentScan(
        value = "com.itheima",
        excludeFilters = @ComponentScan.Filter(
            type= FilterType.ANNOTATION,
            classes = Service.class
            )
        )
    

1.2 自定义导入器(了解)

作用:如果一个类没有使用 @Controller、@Component、@Service、@Repository ,还需要将给类装载到spring核心容器中,

可以使用自定义导入器。

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

//      3.加载import.properties文件中的多个类名
        ResourceBundle bundle = ResourceBundle.getBundle("import");
        String className = bundle.getString("className");
        return className.split(",");
    }
}

1.3 自定义注册器(了解)

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //自定义注册器
        //1.开启类路径bean定义扫描器,需要参数bean定义注册器BeanDefinitionRegistry,需要制定是否使用默认类型过滤器
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry,false);
        //2.添加包含性加载类型过滤器(可选,也可以设置为排除性加载类型过滤器)
        scanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                //所有匹配全部成功,此处应该添加实际的业务判定条件
                return true;
            }
        });
        //设置扫描路径
        scanner.scan("com.itheima");
    }
}

@Import注解的作用:

  • 引入外部的配置类 (掌握)
  • 引入自定义导入器 (了解)
  • 引入自定义注册器 (了解)

2,AOP

课前说明:

如果需要对一个对象中的方法进行动态增强,我们使用动态代理。

现在学习AOP动态代理的代码我们不需要书写了,只需要进行配置即可。

2.1 概述

面向切面编程。是一种范式,一种编程思想。目的:插拔式组件。

spring实现了AOP的思想。

在这里插入图片描述

2.2 AOP术语

重点术语: 连接点 , 切入点 , 通知 , 切面

术语含义
连接点业务类中所有方法
切入点被抽取了共性功能的方法
通知共性功能组成的方法
切面描述的切入点与通知的关系
目标对象原始类创建的对象
通知类型通知的具体在原始功能之前还是之后的位置
织入动态加入共性功能的工作

eg:

上图中的save、delete、update、findAll方法都是连接点。

save、update是切入点。

开启事务、提交|回滚事务组成的方法是通知。

UserService、OrderService、ProductService类对象是目标对象。

2.3 入门案例

  • 引入坐标

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
  • 开发业务功能

    public class UserServiceImpl implements UserService {
    
        public void save(){
            //0.将共性功能抽取出来
            //System.out.println("共性功能");
            System.out.println("user service running...");
        }
    }
    
  • 开发通知类

    public class AOPAdvice {
    
        public void function(){
            System.out.println("共性功能");
        }
    }
    
  • 进行aop的配置

        <!--3.开启AOP命名空间-->
        <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
        <!--2.配置共性功能成功spring控制的资源-->
        <bean id="myAdvice" class="com.itheima.aop.AOPAdvice"/>
    
        <!--4.配置AOP-->
        <aop:config>
            <!--6.配置切面(切入点与通知的关系)-->
            <aop:aspect ref="myAdvice">
                <!--7.配置具体的切入点对应通知中那个操作方法-->
                <aop:before method="function" pointcutf="execution(* *..*(..))"/>
            </aop:aspect>
        </aop:config>
    
  • 测试

    public class App {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService) ctx.getBean("userService");
            userService.save();
        }
    }
    

入门案例执行的流程:

在这里插入图片描述

3,aop的配置(xml)

3.1 切入点表达式

作用: 匹配要增强的方法。

语法:

execution(【修饰符】 返回值类型 包名.类名.方法名(参数类型))

常用的切入点表达式

execution(* *..*(..))
execution(int *..*.*(..))
execution(* com..service.*.*(..))
execution(* com.itheima.service.*.*(..))
execution(User com.itheima.service.UserService.findById(..))
execution(User com.itheima.service.UserService.findById(int))

eg:编写一个切入点表达式,实现事务控制(只对增删改方法增强)

!execution(* com..service.*.find*(..))

3.2 切入点表达式放置的位置

在这里插入图片描述

3.3 通知类型

  • 普通通知 : spring会自动的执行目标方法

    • 前置通知 : 在目标方法执行前执行
      • <aop:before>
    • 后置通知 : 在目标方法执行后执行
      • <aop:after>
    • 返回后通知 : 在目标方法执行后执行,出现异常则不会执行
      • <aop:after-returning>
    • 异常通知 : 在目标方法执行时出现异常时执行
      • <aop:after-throwing>
    <aop:config>
        <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
        <aop:aspect ref="myAdvice">
            <aop:before method="before" pointcut-ref="pt"/>
            <aop:after method="after" pointcut-ref="pt"/>
            <aop:after-returning method="afterReturing" pointcut-ref="pt"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
        </aop:aspect>
    </aop:config>
    
  • 环绕通知 : spring不会自动的执行目标方法,需要我们调用

    • 可以实现上面四个通知的功能
      • <aop:around>
    <aop:config>
        <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
        <aop:aspect ref="myAdvice">
            <aop:around method="around" pointcut-ref="pt"/>
        </aop:aspect>
    </aop:config>
    
    public Object around(ProceedingJoinPoint pjp) {
    
        System.out.println("around before...");
        Object ret = null;
        try {
            //对原始方法的调用
            ret = pjp.proceed();
        } catch (Throwable throwable) {
            System.out.println("around...exception...."+throwable.getMessage());
        }
        System.out.println("around after..."+ret);
        return ret;
    }
    

3.4 获取参数

在通知方法中获取目标方法的参数。

  • 使用JoinPoint(掌握)

    在通知方法上声明一个JoinPoint类型的参数,使用getArgs()方法获取参数。

    public void before(JoinPoint jp){
        //通过JoinPoint参数获取调用原始方法所携带的参数
        Object[] args = jp.getArgs();
    
        Object target = jp.getTarget();//目标对象
    
        Signature signature = jp.getSignature();
        String name = signature.getName();// 获取方法名称
        System.out.println("before..."+args[0]);
    }
    
  • args (了解)

3.5 获取返回值

在通知方法中获取目标方法的返回值。

  • 返回后通知

    在通知方法上声明参数

    public void afterReturing(Object ret){
    	System.out.println("afterReturing..."+ret);
    }
    

    进行配置

    <aop:config>
        <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
        <aop:aspect ref="myAdvice">
            <aop:after-returning method="afterReturing" pointcut-ref="pt" returning="ret"/>
        </aop:aspect>
    </aop:config>
    
  • 环绕通知

    public Object around(ProceedingJoinPoint pjp) {
    
        System.out.println("around before...");
        Object ret = null;
        try {
            //对原始方法的调用
            ret = pjp.proceed();
        } catch (Throwable throwable) {
            System.out.println("around...exception...."+throwable.getMessage());
        }
        System.out.println("around after..."+ret);
        return ret;
    }
    

作业:

进行日志记录。

Point pjp) {

  System.out.println("around before...");
  Object ret = null;
  try {
      //对原始方法的调用
      ret = pjp.proceed();
  } catch (Throwable throwable) {
      System.out.println("around...exception...."+throwable.getMessage());
  }
  System.out.println("around after..."+ret);
  return ret;

}




作业:

进行日志记录。

记录的信息包含 : 方法执行的时间点(2020-10-10 10:20:30),类的全类名,方法名,参数,返回值,异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值