美文网首页spring
关于AOP思想,建议你看看这份五年开发总结的笔记,写的太详细了

关于AOP思想,建议你看看这份五年开发总结的笔记,写的太详细了

作者: 前程有光 | 来源:发表于2020-08-21 14:29 被阅读0次

    前言

    OOP(Object Oriented Programing)面向对象编程

    以对象为基本单位进行程序开发,通过对象间的彼此协同,相互协调,完成程序的构建

    POP(Producer Oriented Programing)面向过程(方法,函数)编程

    以过程为基本单位的程序开发,通过彼此间协同,相互调用,完成程序的构建

    静态代理存在的问题

    //实现相同的接口
    public class UserServiceProxy implements UserService {
        //创建原始对象
        private UserServiceImpl userService = new UserServiceImpl();
        public void register(User user) {
            //实现额外功能
            System.out.println("-------------------");
            userService.register(user);
    
        }
    
        public boolean login(String name, String password) {
            System.out.println("____________________");
            return userService.login(name,password);
        }
    }
    
    

    每一个原始类都会手工编写一个代理类

    • 静态类文件数目过多,不利于项目管理
    • 代码可维护性差

    概述

    上图展示了一个被划分的典型应用,每个模块的核心功能都是为特定业务领域提供服务,但是这些模块都需要类似的辅助功能,例如安全和事务管理。

    如果要重用通用功能的话,最常见的面向对象技术是继承或者委托。但是,如果在整个应用中都使用相同的基类,继承往往会导致一个脆弱的对象体系,而使用委托可能需要对委托对象进行复杂的调用。


    切面提供了取代继承和委托的另一种可选方案,而且在很多场景下更清晰简洁,在使用面向切面编程时,我们仍然在一个地方定义通用功能,但是可以通过声明的方式定义这个功能要以何种方式在何处应用,而无需修改受影响的类,横切关注点模块化为特殊的类,这些类被称为切面(aspect)。这样做有两个好处:首先,现在每个关注点都集中在一个地方,而不是分散到多处代码;其次,服务模块更简洁,因为它们只包含主要关注点(或者核心功能)的代码,而次要关注点的代码被移转到切面中了。

    AOP不可能取代 OOP,它只是OOP的有意补充

    Spring中的AOP

    AOP:本质上就是 Spring动态代理开发,有益于原始类的维护

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。

    如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的,诸如private的方法也是不可以作为切面的。

    JDK动态代理的实现

    代理创建三要素:1 原始对象 2 额外功能 3 代理对象实现相同的接口

    JDK动态代理的核心是InvocationHandler接口和Proxy类。

    public static void main(String[] args) {
        //创建原始对象
        UserService userService = new UserServiceImpl();
        //JDK创建动态代理
            Proxy.newProxyInstance(ClassLoader ,interfaces, invocationHandler)
    }
    
    
    public interface InvocationHandler {
        //用于书写额外功能 额外功能:原始方法执行前后 抛出异常
        // 参数:Proxy 忽略掉,表示的是代理对象
        //method 额外功能所增加给的那个原始方法
        //Object[] args 原始方法的参数
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    
    

    interfaces:原始对象所实现的接口
    userService.getClass().getInterfaces()

    类加载器的作用:

    • 通过类加载器把对应类的字节码加载到JVM中
    • 通过类加载器创建class对象,进而创建这个类的对象

    如何获得类加载器:每个类的.class文件 自动分配与之对应的ClassLoder

    在动态代理创建的过程中,需要ClassLoader创建代理类的Class对象,可是动态代理类没有对应的.class文件,JVM也不会为其分配ClassLoader,但是又需要怎么办?(借用一个ClossLoader)

    ClassLoader:完成代理类的创建
    创建代理类的class对象,进而完成代理类的创建

    //注意:类加载器是借用来的 可以随表找一个借用
    // 在JDK8.0之前 内部变量访问外部变量需要加final
    public class JDKProxy {
        public static void main(String[] args) {
            final UserService  userService = new UserServiceImpl();
            InvocationHandler handler = new InvocationHandler() {
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("-----login-------");
                    //原方法运行
                    Object obj = method.invoke(userService, args);
                    return obj;
                }
            };
            UserService service = (UserService) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
            service.login("gewei","hello");
            service.register(new User());
        }
    }
    
    

    CGlib动态代理的实现

    对于一些没有实现接口的方法

    public class UserServiceImpl(){
        login();
        register();
    }
    
    

    代理类 继承你要代理的类

    public clss Proxy extends UserServiceImpl(){
        login(){
            额外功能
            super.login();
        }
    }
    
    
    public class TestCglib {
        public static void main(final String[] args) {
            //创建原始对象
           final UserService userService = new UserService();
        /*
            通过cglib方式创建动态代理对象
            Proxy.newProxyInstance(ClassLoader ,interfaces, invocationHandler)
            cglib同样也需要做这些:
            enhancer.setClassLoader();
            enhancer.setSuperclass();
            enhancer.setCallback(); -->MethodInterceptor(cglib包下)
    
         */
            Enhancer enhancer = new Enhancer();
            enhancer.setClassLoader(TestCglib.class.getClassLoader());
            enhancer.setSuperclass(userService.getClass());
    
            MethodInterceptor interceptor = new MethodInterceptor() {
                //等同于 InvocationHandler -- invoke
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    System.out.println("hello world");
                    Object invoke = method.invoke(userService, args);
                    return invoke;
                }
            };
            enhancer.setCallback(interceptor);
            UserService userServiceProxy = (UserService) enhancer.create();
            userServiceProxy.login();
            userServiceProxy.register();
    
        }
    
    }
    
    

    Spring中基于AspectJ注解的AOP编程

    环境搭建

    
        <!-- 1.配置扫描的基包  -->
        <context:component-scan base-package="com.itheima"/>
    
        <bean id="Aspectj" class="cn.gewei.factory.Aspectj"></bean>
        //打开注解开发
    <aop:aspectj-autoproxy/>
    
    

    环绕通知

    /**
     * 次要的业务:切面类
     */
    @Component  //把这个类加到Spring容器中
    @Aspect  //这个类是切面类
    public class LogAspect {
    
        @Pointcut("execution(* com.itheima.service..*.*(..))")   //切面表达式,这是一个空方法,作用:创建切面表达式的
        public void pt() {
        }
    
        /**
         * 环绕通知
         */
        @Around("pt()")
        public Object around(ProceedingJoinPoint joinPoint) {
            Object result = null;
            try {
                System.out.println("前置通知");
                //调用目标方法
                result = joinPoint.proceed();
                System.out.println("后置通知");
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                System.out.println("异常通知");
            } finally {
                System.out.println("最终通知");
            }
            //返回方法的返回值
            return result;
        }
    }
    
    

    前置,后置,异常,最终通知

    /**
     * 次要的业务:切面类
     */
    @Component  //把这个类加到Spring容器中
    @Aspect  //这个类是切面类
    public class LogAspect {
    
        @Pointcut("execution(* com.itheima.service..*.*(..))")   //切面表达式,这是一个空方法,作用:创建切面表达式的
        public void pt() {
        }
    
        @Before("pt()")
        public void before() {
            System.out.println("前置通知");
        }
    
        @AfterReturning("pt()")
        public void afterReturn() {
            System.out.println("后置通知");
        }
    
        @AfterThrowing("pt()")
        public void afterThrowing() {
            System.out.println("异常通知");
        }
    
        @After("pt()")
        public void after() {
            System.out.println("最终通知");
        }
    }
    
    

    切入点复用

    @Pointcut("execution(* *(..))")
    public void pointcut(){}
    
    @Around(value = "pointcut()")
    
    

    默认情况下Spring底层是JDK动态代理实现的

    //将proxy-target-class设为true就是基于Cglib的开发模式
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
    

    小结

    AOP是面向对象编程的一个强大补充。通过Spring的动态代理,我们现在可以把之前分散在应用各处的行为放入可重用的模块中。我们显示地声明在何处如何应用该行为。这有效减少了代码冗余,并让我们的类关注自身的主要功能。

    AOP编程概念(Spring动态代理开发),通过代理类为原始类增加额外的功能,好处:利于原始类的维护。

    最后

    感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

    相关文章

      网友评论

        本文标题:关于AOP思想,建议你看看这份五年开发总结的笔记,写的太详细了

        本文链接:https://www.haomeiwen.com/subject/rfpujktx.html