Java AOP动态代理详细介绍

 更新时间:2022年08月25日 16:00:00   作者:青柠果  
AOP是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善。本文将用Java实现AOP代理的三种方式,需要的可以参考一下

1.IOC与AOP概念

IOC:控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理。使用IOC的目的是为了降低耦合度。

AOP:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。AOP的底层实现是基于动态代理(实现方式是当切入接口时,使用JDK原生动态代理;当切入普通方法时,使用cglib动态代理)。

2.为何使用动态代理

随着业务的不断扩展:

(1)日志功能:如果日志代码修改,需要修改多处。

(2)校验功能:如果多处需要校验,需要修改多处。

这时就需要使用动态代理来解决问题,动态代理的实现方式有两种:

[1]JDK原生动态代理:缺点是必须基于接口完成

[2]cglib动态代理:他可以不用基于接口完成

2.1 JDK原生动态代理

2.1.1 MathService接口类

public interface MathService {
    //+
    public Double add(double a,double b);
    //-
    public Double sub(double a,double b);
    //*
    public Double mul(double a,double b);
    ///
    public Double div(double a,double b);
}

2.1.2 MathServiceImpl实现接口类

public class MathServiceImpl implements MathService{
    @Override
    public Double add(double a, double b) {
        Double result=a+b;
        return result;
    }
    @Override
    public Double sub(double a, double b) {
        Double result=a-b;
        return result;
    }
    @Override
    public Double mul(double a, double b) {
        Double result=a*b;
        return result;
    }
    @Override
    public Double div(double a, double b) {
        Double result=a/b;
        return result;
    }
}

2.1.3 ProxyFactory动态代理工厂

public class ProxyFactory {
    //被代理对象
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    //获取代理对象
    public Object getProxy(){
        /**
         * ClassLoader loader, 被代理对象的类加载器
         * Class<?>[] interfaces, 被代理对象实现的接口
         * InvocationHandler h: 当代理对象执行被代理的方法时,会触发该对象中的invoke功能
         */
        ClassLoader loader=target.getClass().getClassLoader();
        Class<?>[] interfaces=target.getClass().getInterfaces();
        InvocationHandler h=new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //可以加上需要的非业务代码
                //method.getName()获取方法名
                // Arrays.asList(args)获取输入值
                System.out.println("this is "+method.getName()+" method begin with"+ Arrays.asList(args));
                //method:表示代理对象要代理的方法
                //invoke:回调该函数
                //args:方法需要的参数
                Object result = method.invoke(target, args);//代理对象回调该方法
                return result;
            }
        };
        //先写此处方法,才可找到上述三个方法填写方式
        Object o = Proxy.newProxyInstance(loader, interfaces, h);
        return o;
    }
}

2.1.4 测试类

public class Test01 {
    public static void main(String[] args) {
        MathServiceImpl target=new MathServiceImpl();
        ProxyFactory proxyFactory=new ProxyFactory(target);
        MathService proxy = (MathService) proxyFactory.getProxy();
        Double add = proxy.add(15.0, 5.0);
        System.out.println(add);
    }
}

2.2 cglib动态代理

2.2.1 MathServiceImpl类

public class MathServiceImpl{
    public Double add(double a, double b) {
        Double result=a+b;
        return result;
    }
    public Double sub(double a, double b) {
        Double result=a-b;
        return result;
    }
    public Double mul(double a, double b) {
        Double result=a*b;
        return result;
    }
    public Double div(double a, double b) {
        Double result=a/b;
        return result;
    }
}

2.2.2 ProxyFactory动态代理工厂

注意:

(1)引入cglib的jar包.

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.2.5</version>
</dependency>  

(2)创建一个代理类工厂并实现接口MethodInterceptor

public class ProxyFactory implements MethodInterceptor {
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    //获取代理对象
    public Object getProxy(){
        Enhancer enhancer=new Enhancer();
        //指定被代理对象的父类
        enhancer.setSuperclass(target.getClass());
        //指定回调类
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }
    //当代理对象执行代理方法时触发的方法
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//        System.out.println("before++++++++++++++++++++");
//        Object result = method.invoke(target, args);
        //可以加上需要的非业务代码
        //method.getName()获取方法名
        // Arrays.asList(args)获取输入值
        System.out.println("this is "+method.getName()+" method begin with"+ Arrays.asList(args));
        //method:表示代理对象要代理的方法
        //invoke:回调该函数
        //args:方法需要的参数
        Object result = method.invoke(target, args);//代理对象回调该方法
        return result;
    }
}

2.2.3 测试类

public class Test01 {
    public static void main(String[] args) {
        MathServiceImpl target=new MathServiceImpl();
        ProxyFactory proxyFactory=new ProxyFactory(target);
        MathServiceImpl proxy = (MathServiceImpl) proxyFactory.getProxy();
        Double add = proxy.add(1, 2);
        System.out.println(add);
    }
}

3.AOP动态代理

3.1 添加对应依赖

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.15.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.15.RELEASE</version>
    </dependency>

3.2 配置spring.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--包扫描-->
    <context:component-scan base-package="com.qy151wd.proxy.proxy.aop"/>
    <!--开启aop注解-->
    <aop:aspectj-autoproxy/>
</beans>

3.3 MathService接口类

public interface MathService {
    public Double add(double a, double b);
    public Double sub(double a, double b);
    public Double mul(double a, double b);
    public Double div(double a, double b);
}

3.4 MathServiceImpl实现接口类

@Service
public class MathServiceImpl implements MathService {
    @Override
    public Double add(double a, double b) {
        Double result=a+b;
        return result;
    }
    @Override
    public Double sub(double a, double b) {
        Double result=a-b;
        return result;
    }
    @Override
    public Double mul(double a, double b) {
        Double result=a*b;
        return result;
    }
    @Override
    public Double div(double a, double b) {
        Double result=a/b;
        return result;
    }
}

3.5 LogAspect类

@Service //若是使用@component也可以
@Aspect //表示该类为切面类
public class LogAspect {
    //任意返回类型 aop包下的所有类都有切面日志 使用通配符
    //第一个*:修饰符和返回值类型
    //第二个*:所有类
    //第三个*:所有方法
    @Before("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))")
    public void before(){
        System.out.println("方法执行前的日志");
    }
    @After("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))") //总会被执行,不管有没有异常
    public void after(){
        System.out.println("方法执行后的日志");
    }
    @AfterReturning("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))")//只有碰到return后才会执行
    public void afterReturning(){
        System.out.println("碰到return后执行");
    }
    @AfterThrowing("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))")//异常通知
    public void afterThrowing(){
        System.out.println("出现异常了");
    }
}

3.6 测试类

public class Test01 {
    public static void main(String[] args) {
        //从spring容器中获取
        ApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        MathService mathService = (MathService) app.getBean("mathServiceImpl");
        Double add = mathService.add(10, 5);
        System.out.println(add);
    }
}

到此这篇关于Java AOP动态代理详细介绍的文章就介绍到这了,更多相关Java AOP动态代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一次线上websocket返回400问题排查的实战记录

    一次线上websocket返回400问题排查的实战记录

    最近项目中有端对端通信场景,实时性要求较高,考虑后选用了websocket 这一通信协议,下面这篇文章主要给大家介绍了一次线上websocket返回400问题排查的实战记录,需要的朋友可以参考下
    2022-04-04
  • 浅谈cookie和session(小结)

    浅谈cookie和session(小结)

    这篇文章主要介绍了浅谈cookie和session(小结),cookie和session在java web开发中扮演了十分重要的作用,本篇文章对其中的重要知识点做一些探究和总结
    2018-11-11
  • Java判断字符串是否为IP地址的方法

    Java判断字符串是否为IP地址的方法

    这篇文章主要为大家详细介绍了Java判断字符串是否为IP地址的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • Servlet服务端实现原理详解

    Servlet服务端实现原理详解

    Servlet是Sun公司开发动态web的一门技术,Sun公司在这些API中提供了一个接口叫做:Servlet,如果想开发一个Servlet程序,只需要完成两个小步骤:编写一个类,实现Servlet接口、把开发好的Java类部署到web服务器中。但是你了解Servlet实现的原理吗
    2022-07-07
  • 解决fastjson泛型转换报错的解决方法

    解决fastjson泛型转换报错的解决方法

    这篇文章主要介绍了解决fastjson泛型转换报错的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • java中下拉框select和单选按钮的回显操作

    java中下拉框select和单选按钮的回显操作

    这篇文章主要介绍了java中下拉框select和单选按钮的回显操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • java多态实现电子宠物系统

    java多态实现电子宠物系统

    这篇文章主要为大家详细介绍了java多态实现电子宠物系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • spring通过构造函数注入实现方法分析

    spring通过构造函数注入实现方法分析

    这篇文章主要介绍了spring通过构造函数注入实现方法,结合实例形式分析了spring通过构造函数注入的原理、实现步骤及相关操作注意事项,需要的朋友可以参考下
    2019-10-10
  • 详解Java中运算符及用法

    详解Java中运算符及用法

    这篇文章主要介绍了详解Java中运算符以及相关的用法讲解,一起跟着小编学习下吧。
    2017-12-12
  • java计算代码段执行时间的详细代码

    java计算代码段执行时间的详细代码

    java里计算代码段执行时间可以有两种方法,一种是毫秒级别的计算,另一种是更精确的纳秒级别的计算,这篇文章主要介绍了java计算代码段执行时间,需要的朋友可以参考下
    2022-08-08

最新评论