第十四章、AOP编程实现原理

1.AOP概念

AOP (Aspect Oriented Programing)

⾯向切⾯编程 = Spring动态代理开发

以切⾯为基本单位的程序开发,通过切⾯间的彼此协同,相互调⽤,完成程序的构建
切⾯ = 切⼊点 + 额外功能

OOP (Object Oritened Programing)
⾯向对象编程 Java
以对象为基本单位的程序开发,通过对象间的彼此协同,相互调⽤,完成程序的构建

POP (Producer Oriented Programing)
⾯向过程(⽅法、函数)编程 C
以过程为基本单位的程序开发,通过过程间的彼此协同,相互调⽤,完成程序的构建

AOP的概念:
本质就是Spring的动态代理开发,通过代理类为原始类增加额外功能。
好处:利于原始类的维护
注意:AOP编程不可能取代OOP,是对OOP编程的补充。

2.AOP编程的开发步骤

  1. 原始对象
  2. 额外功能 (MethodInterceptor)
  3. 切⼊点
  4. 组装切⾯ (额外功能+切⼊点)

3.切面的名词解释

切⾯ = 切⼊点 + 额外功能
在这里插入图片描述

AOP底层实现原理

1.核心问题

  1. AOP如何创建动态代理类(动态字节码技术)?(第二节解释它)

  2. Spring⼯⼚如何加⼯创建代理对象?(第三节解释它)
    通过原始对象的id值,获得的是代理对象

2.动态代理类的创建(第二节)

2.1 JDK的动态代理

类加载器(ClassLoader)
创建user对象的过程(分析User user = new User();过程):
步骤:

  1. 创建源文件User.java
  2. 编译成User.class文件 含有User类对应的字节码
  3. 创建对象和运行对象必须在JVM当中的,所以通过类加载器将字节码读取到jvm中,在jvm中先创建User类的Class对象(这个过程也是类加载器完成的),Class对象含有User类的所有信息,进而创建对象user。
    图解如下:
    在这里插入图片描述
    在这里插入图片描述
    动态代理类没有.java和.class文件,所以没有加载字节码的过程,通过动态字节码技术直接将字节码创建在jvm中。因为没有.class文件,所以jvm没有分配类加载器,没有类加载器就不能生成Class对象,也就不能创建代理类对象。
    如何获得类加载器呢? 借用一个!
    Proxy.newProxyInstance(classloader,interfaces,invocationhandler)借用的类加载器从第一个参数classloader传进去。
Proxy.newProxyInstance(classloader,interfaces,invocationhandler)详解如下图:
	1. 第一个参数classloader:借用的类加载器
	2. 第二个参数interfaces:通过反射获得原始对象的接口。(因为代理对象要和原始对象实现相同的接口。)
	3. 第三个参数invocationhandler:通过反射实现额外功能。        
               		 //invoke :激活的意思  传递参数
        			//方法名.invoke(对象,方法的值); setName.invoke(user3,"豆豆");

在这里插入图片描述

2.2 JDK动态代理编码

public class TestJDKProxy {
    public static void main(String[] args) {
        //研究原理 就不用Spring框架创建对象了
        // 1. 创建原始对象。
        final UserService userService = new UserServiceImpl();
        //2.JDK创建动态代理
        //借用的类加载器可以是这里的TestJDKProxy的也可以是UserServiceImpl的
        //InvocationHandler是个接口,接口不能new,这里通过内部类实现实现接口。实现接口的invoke方法
        InvocationHandler handler  = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("运行之前额外功能");
                //原始方法运行
                Object ret = method.invoke(userService, args);

                return ret;
            }
        };
        //动态代理类对象serServiceProxy
  UserService userServiceProxy = (UserService)Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        userServiceProxy.login();
        userServiceProxy.register();
    }
}

2.3 CGlib的动态代理

CGlib创建动态代理的原理:⽗⼦继承关系创建代理对象,原始类作为⽗类,代理类作为⼦类,
这样既可以保证两者⽅法⼀致,同时在代理类中提供新的实现(额外功能+原始⽅法)方法;
jdk和CGlib区别如下图:
在这里插入图片描述
CGlib编码:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class TestCglib {
    public static void main(String[] args) {
        final UserService userService = new UserService();
        Enhancer enhancer = new Enhancer();
        //借用类加载器
        enhancer.setClassLoader(TestCglib.class.getClassLoader());
        //继承父类UserService
        enhancer.setSuperclass(userService.getClass());

        //实现接口MethodInterceptor   通过匿名内部类 等同于InvocationHandler --- invoke
        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            //实现额外功能
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("TestCglib.intercept 原始功能运行之前");
                Object ret = method.invoke(userService, args);
                return ret;
            }
        };

        //setCallback()对应的是额外功能 通过参数interceptor传进来
        enhancer.setCallback(interceptor);

        //创建动态代理对象 代理类继承了原始类 所以可以用原始类创建代理对象
        UserService userServiceProxy = (UserService) enhancer.create();

        userServiceProxy.login("suns","111");
        userServiceProxy.register(new User());


    }
}

总结

  1. JDK动态代理
    Proxy.newProxyInstance() 通过接⼝创建代理的实现类
  2. Cglib动态代理 Enhancer
    通过继承⽗类创建的代理类

3.Spring⼯⼚如何加⼯原始对象(第三节)

思路分析:在BeanPostProcessor的postProcessAfterinitialization方法里创建代理类对象,返回给Spring工厂。(不做初始化操作。)
在这里插入图片描述
编码分析:

步骤一:java编码:
    1.创建接口
    public interface UserService {
    public void login(String name,String password);
    public void register(User user);

}
	2.原始类
    public class UserServiceImpl implements UserService{
    public void login(String name,String password){
        System.out.println("UserServiceImpl.login");
    }
    public void register(User user){
        System.out.println("UserService.register");
    }
}
	3.动态代理类
public class ProxyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;//注意不能返回null 要把原始对象传到初始化再传给postProcessAfterInitialization
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //内部类
        InvocationHandler handler=new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //bean是第7行的第一个参数bean:原始对象
                System.out.println("new ----log");
                Object ret = method.invoke(bean, args);
                return ret;
            }
        };
        return  Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(), handler); //返回代理类对象
    }

}

步骤二:配置文件
    原始对象:
<bean id="userService"class="com.baizhiedu.factory.UserServiceImpl"/>
    加工后的对象:
<bean id="proxyBeanPostProcessor" class="com.baizhiedu.factory.ProxyBeanPostProcessor"/>

步骤三:测试
    虽然拿的是原始对象的id值,但是获得的是代理对象。(通过BeanPostProcessor对原始对象进行了再加工)
    public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext3.xml");
        UserService userService = (UserService) ctx.getBean("userService");
        userService.login("suns","111");
        userService.register(new User());
    }
}

本系列文章从Spring5原理开始深入浅出,从工厂特性=>依赖注入–IOC=>AOP编程=>Spring事务=>纯注解开发。本文来自观看B站孙帅Spring教程后做的笔记。持续更新…

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值