Java AOP动态代理详细介绍

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原生动态代理

IiBzcmM9

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动态代理

IiBzcmM9

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动态代理

IiBzcmM9

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动态代理内容请搜索编程学习网以前的文章希望大家以后多多支持编程学习网!

本文标题为:Java AOP动态代理详细介绍