AOP编程底层核心解析

2023-12-27 16:31:06

说到AOP不得不介绍一下Spring 的核心三大件:IOC、DI、AOP
1、Spring的核心思想:

IOC:Inversion Of Control,控制反转(将bean的生命周期的维护交给spring容器管理了。)

DI:Dependency Injection,依赖注入( IoC 容器在运?期间,动态地将某种依赖关系注?到对象之中,注入方式:属性、构造方法、set方法注入。)

AOP:Aspect Oriented Programming,面向切面编程(以切面为基本单位的程序开发,切面=切入点 + 需要加入的功能组成)

2、面向切面编程(AOP)底层实现是什么?有了面向对象编程(OOP),为什么还要个AOP?

动态代理;OOP是以对象为基本单位的开发,AOP是对它进行补充增强【这也是代理设计模式的核心思想,代理对象,并对被代理的对象进行无侵入性功能增强】,OOP不是不可以应付,只是实现起来会很麻烦,耦合性会增强、复用性会降低,一定程度上违背了面向对象思想的基本原则。

3、主流的动态代理的分类有哪些?

基于JDK实现的动态代理、基于cglib第三方包实现的动态代理

4、基于JDK实现的动态代理代码案例:

接口示例
package com.spring.stu.proxy;

public interface UserService {
    String login(String username, String passwd);
    String logout(String username);
}
实现示例
package com.spring.stu.proxy;

public class UserServiceImpl implements UserService{
    @Override
    public String login(String username, String passwd) {
        System.out.println("-------------login---------------");
        return "OK";
    }

    @Override
    public String logout(String username) {
        System.out.println("-------------logout---------------");
        return "OK";
    }
}

JDK的动态代理实现以及注释
package com.spring.stu.proxy;

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

public class UserJDKDynamicProxy {

    public static void main(String[] args) {

        UserService userService = new UserServiceImpl();

        /**
         * 这里就是代理处理实例,我们做代理是为了什么?就是为了:无缝增强功能
         * 这里面就可以对具体需要给那些需要增强功能的方法做具体的处理了
         */
        InvocationHandler handler = new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //这里只用关注:Method method, Object[] args 这两个参数即可,代理对象不用关注
                Object result = method.invoke(userService, args);
                //获取到方法名,定向增强
                String methodName = method.getName();

                //多方法自定义的进行分别处理
                if (methodName.equalsIgnoreCase("login")) {
                    System.out.println("----login-----》》》 我在这里实现了增强,增加了功能。");

                } else {
                    System.out.println("---logout------》》》 我在后面实现了增强,增加了功能。");

                }

                return result;
            }
        };

        /**
         * 三个参数:
         * ClassLoader:随便搞个ClassLoader即可,就是一个将字节码文件动态搞到jvm里面去的工具
         * Interface:jdk的代理是基于父接口的,不是基于具体实现的,所以这里要传入接口的字节码文件
         * InvocationHandler:调用的处理程序,这里面去增强功能
         */
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        userServiceProxy.login("li si", "1111111");

        System.out.println("-----------------------------------------------------------");

        userServiceProxy.logout("li si");

    }



}

4、基于cglib第三方包实现的动态代理:
注意:如果是普通java工程需要导入cglib的第三方jar包,jdk不提供的;如果是spring工程,默认就引入了cglib的报,无需重复引入。

package com.spring.stu.proxy;

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 CglibDProy {

    public static void main(String[] args) {

        /**
         * 这里是基于具体实现类的,不是基于接口的,如果有父接口也行
         * cglib的场景就是没有接口,只有具体实现类的场景
         */
        UserServiceImpl userService = new UserServiceImpl();

        //cglib核心类
        Enhancer enhancer = new Enhancer();
        //类加载器:随便找一个都可以,当前类的、或者被代理对象的,就是一个将class字节码load到jvm的工具,Classloader 也只有这个作用,比Class.forName(class)弱了很多
        //打个比方:ClassLoader 只管把你带进门【jvm】,后续你自己爱干嘛干嘛;Class.forName(class字节码) 会一直跟着你,把你实例化完成,比如:对象属性都要实例化并赋值完成,管杀又管埋的保姆
        enhancer.setClassLoader(UserService.class.getClassLoader());
        //需要被代理类的字节码文件,或者父类文件
        enhancer.setSuperclass(userService.getClass());

        /**
         * 组装切面或者切入点
         */
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

                String methodName = method.getName();

                //args :方法需要传入的参数,这里的method其实就是方法的代理实例,可以debug看到里面的具体参数;userService:具体需要代理的的对象
                Object result = method.invoke(userService, args);

                if (methodName.equalsIgnoreCase("login")) {
                    System.out.println("----login 方法单独处理-----》》》 我在这里实现了增强,增加了功能。");

                } else {
                    System.out.println("----logout-----》》》 我在后面实现了增强,增加了功能。");
                }
                return result;
            }
        };

        enhancer.setCallback(methodInterceptor); //这里就是真正想要增强的功能
        UserServiceImpl userServicecp = (UserServiceImpl) enhancer.create();
        userServicecp.login("zhang san", "123456");

    }
}

5:jdk动态代理和cglib动态代理的对比

  • 其实这两种代理方法,模式几乎都是一样的:Classloader、接口/类、具体处理的实例方法处理对象,都需要传入三类参数;
  • JDK的动态代理是基于接口(implements)的代理,而cglib是基于类(extends)的代理,他们并无好坏之分,只是使用场景的区别,自己选择即可,适合的才是最好的。
  • Spring aop 使用的是jdk的动态代理。

文章来源:https://blog.csdn.net/qq_35543206/article/details/135242841
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。