文章已托管到GitHub,大家可以去GitHub查看阅读,欢迎老板们前来Star!

搜索关注微信公众号 码出Offer 领取各种学习资料!

SpringAOP


一、什么是AOP

二、场景分析

首先,我们要先理解什么是日志。

日志: 日志是一种可以追踪某些软件运行时所发生事件的方法,软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情。一个事件可以用一个可包含可选变量数据的消息来描述,此外,事件也有重要性的概念,这个重要性也可以被称为严重性级别(level)。开发者可以通过区分严重性级别来分析出想要的信息。

了解了什么是日志,那就要知道怎么打印日志,在哪里打印日志。打印日志,是引入依赖,使用日志工具来实现日志严重性级别和日志信息的打印。至于在哪里打印日志,当然是在我们项目代码中的关键位置了。

三、AOP术语

四、AOP术语解析

3.1 连接点

3.2 切入点

3.3 增强、通知

3.4 目标对象

3.5 引介

3.6 织入

3.7 代理

3.8 切面

五、SpringAOP开发步骤

5.1 pom.xml文件引入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

5.2 创建spring-context.xml文件并添加schema

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       "
>
</beans>

5.3 定义原始类

public interface UserService {
    public void save();
}

public class UserServiceImpl implements UserService {
    public void save() {
        System.out.println("save method executed...");
    }
}

5.4 定义通过类

public class MyAdvice implements MethodBeforeAdvice //实现前置通知接口
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before advice executed...");
    }
}

5.5 定义bean

<!--原始对象-->
<bean id="us" class="com.mylifes1110.service.impl.UserServiceImpl" />

<!--辅助(增强)对象-->
<bean id="myAdvice" class="com.mylifes1110.advice.MyAdvice" />

5.6 定义切入点形成切面

<aop:config>
    <!--切点-->
    <aop:pointcut id="myPointCut" expression="execution(* save())" />
    <!--组装切面-->
    <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" />
</aop:config>

5.7 增强结果

六、通知

七、通配切入点

<!-- public int com.mylifes1110.service.UserServiceImpl.queryUser(int,String,com.entity.User) -->
<!--匹配参数-->
<aop:pointcut id="myPointCut" expression="execution(* *(com.mylifes1110.bean.User))" />
<!--匹配方法名(无参)-->
<aop:pointcut id="myPointCut" expression="execution(* save())" />
<!--匹配方法名(任意参数)-->
<aop:pointcut id="myPointCut" expression="execution(* save(..))" />
<!--匹配返回值类型-->
<aop:pointcut id="myPointCut" expression="execution(com.mylifes1110.bean.User *(..))" />
<!--匹配类名-->
<aop:pointcut id="myPointCut" expression="execution(* com.mylifes1110.bean.UserServiceImpl.*(..))" />
<!--匹配包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.mylifes1110.bean.*.*(..))" />
<!--匹配包名、以及子包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.mylifes1110..*.*(..))" />

八、代理模式

8.1 代理模式

8.2 代理模式应用场景模拟

场景模拟: 我们在租赁房子需要走如下流程:

  1. 发布租房信息
  2. 带租户看房
  3. 签合同
  4. 收房租

可如果你是房东,生活中还有其他的琐事,怎么办呢?那你是不是可以把不重要不核心的环节交给中介(代理)去做呢?比如:发布租房信息和带租户看房。这两件事情交给中介去做就好了,我们自己处理自己的事情,而且中间联系好租户我们走比较重要的流程就可以,比如签合同、收房租。

8.3 创建Service接口和实现类

package com.mylifes1110.service;

public interface LandlordService {
    void rent();
}

package com.mylifes1110.service.impl;

import com.mylifes1110.service.LandlordService;

public class LandlordServiceImpl implements LandlordService {
    @Override
    public void rent() {
        System.out.println("签合同");
        System.out.println("收款");
    }
}

8.4 静态代理

package com.mylifes1110.advice1;

import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;

/**
 * @ClassName Proxy
 * @Description 静态代理类
 * @Author Ziph
 * @Date 2020/7/19
 * @Since 1.8
 * @Version 1.0
 */


public class Proxy implements LandlordService {
    private LandlordService landlordService = new LandlordServiceImpl();

    @Override
    public void rent() {
        // 代理事件
        System.out.println("发布消息");
        System.out.println("看房子");
        // 核心事件
        landlordService.rent();
    }
}
package com.mylifes1110.advice1;

import org.junit.Test;

public class ProxyTest {
    /**
     * @MethodName proxyTest
     * @Param []
     * @Description 静态代理实现
     * @Author Ziph
     * @Date 2020/7/10
     */

    @Test
    public void proxyTest() {
        new Proxy().rent();
    }
    /**
     * 结果:
     * 
     * 发布消息
     * 看房子
     * 签合同
     * 收款
     */

}

8.5 JDK和CGLIB的选择

class DefaultAopProxyFactory{
    // 该方法中明确定义了 JDK代理和CGLib代理的选取规则
    // 基本规则是:目标业务类如果有接口则用JDK代理,没有接口则用CGLib代理
    public AopProxy createAopProxy(){...}
}

8.6 JDK动态代理

package com.mylifes1110.advice2;

import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;
import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {
    /**
     * @MethodName proxyTest
     * @Param []
     * @Description JDK动态代理实现
     * @Author Ziph
     * @Date 2020/7/10
     */

    @Test
    public void proxyTest() {
        // 需要使用代理的目标
        LandlordService landlordService = new LandlordServiceImpl();
        // 匿名内部类
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 代理事件
                System.out.println("发布消息");
                System.out.println("看房子");
                return method.invoke(landlordService, args);
            }
        };

        // 动态构建代理类
        LandlordService proxy = (LandlordService) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),
                landlordService.getClass().getInterfaces(),
                handler);

        proxy.rent();

        /**
         * 结果:
         *
         * 发布消息
         * 看房子
         * 签合同
         * 收款
         */

    }
}

8.7 CGLIB动态代理

package com.mylifes1110.advice3;

import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;

/**
 * @ClassName ProxyTest
 * @Description CGLIB动态代理实现
 * @Author Ziph
 * @Date 2020/7/19
 * @Since 1.8
 * @Version 1.0
 */


public class ProxyTest {
    public static void main(String[] args) {
        final LandlordService landlordService = new LandlordServiceImpl();
        // 创建字节码增强对象
        Enhancer enhancer = new Enhancer();
        // 设置父类(等价于实现原始类接口)
        enhancer.setSuperclass(landlordService.getClass());
        // 设置回调函数(额外功能代码)
        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                // 代理事件
                System.out.println("发布消息");
                System.out.println("看房子");
                Object ret = method.invoke(landlordService, args);
                return ret;
            }
        });
        // 创建动态代理类
        LandlordService proxy = (LandlordService) enhancer.create();
        proxy.rent();
        /**
         * 结果:
         *
         * 发布消息
         * 看房子
         * 签合同
         * 收款
         */

    }
}

九、后处理器

9.1 后处理器的了解

9.2 定义后处理器

/**
 * 定义bean后处理器
 * 作用:在bean的创建之后,进行再加工
 */

public class MyBeanPostProcessor implements BeanPostProcessor{

    /**
     * 在bean的init方法之前执行
     * @param bean  原始的bean对象
     * @param beanName
     * @return
     * @throws BeansException
     */

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后处理器 在init之前执行~~~" + bean.getClass());
        return bean;
    }
    /**
     * 在bean的init方法之后执行
     * @param bean  postProcessBeforeInitialization返回的bean
     * @param beanName
     * @return
     * @throws BeansException
     */

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后处理器 在init之后执行~~~" + bean.getClass());
        return bean;// 此处的返回是 getBean() 最终的返回值
    }
}

9.3 配置后处理器

<!-- 配置后处理器,将对工厂中所有的bean声明周期进行干预 -->
<bean class="com.mylifes1110.beanpostprocessor.MyBeanPostProcessor"></bean>

9.4 Bean的生命周期

9.5 动态代理源码(了解)

// AbstractAutoProxyCreator是 AspectJAwareAdvisorAutoProxyCreator的父类
// 该后处理器类中的 wrapIfNecessary方法即动态代理生成过程
AbstractAutoProxyCreator#postProcessAfterInitialization(Object bean, String beanName){
    if (!this.earlyProxyReferences.contains(cacheKey)) {
        // 开始动态定制代理
        return wrapIfNecessary(bean, beanName, cacheKey);
       }
}

记得关注我哦!拜拜,下期见!

07-19 19:27