乐趣区

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

前言

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 相干技术文章或行业资讯,欢送大家关注和转发文章!

退出移动版