Spring解析(中篇)Aop解析(动态代理)

本文介绍了面向切面编程(AOP)的概念,AOP在Java中通过动态代理实现,旨在规范化编程,提高代码可维护性和可读性。文章详细阐述了动态代理的优势,包括在不修改源码的情况下增强方法,并提供了基于JDK和CGLIB两种动态代理的实现示例。通过这两个示例,展示了如何在方法调用前后添加额外的功能,如日志和事务管理。
摘要由CSDN通过智能技术生成

SpringAop解析(上)


Aop(Aspect Oriented Programming):面向切面编程

在Aop的底层是基于一个动态代理的模式来实现的,简单来说,Aop就是一个规范化的动态代理。

为什么这么说呢?因为在Java中,动态代理本身是一项十分灵活的技术,越灵活的技术掌握难度自然也越高。在使用传统的方式创建代理的时候,是可以有多种表达的形式的,两个人可能会有两种不同的表达形式,这样在项目中可能会碰到一些不必要的麻烦,于是便有人将它进行了一种规范化,将它的表达形式进行了一个统一,让它在掌握时更加的容易,在使用的时候更加的轻松。

面向切面编程,将交叉业务逻辑代码封装成切面,利用Aop容器的功能将切面放到主业务逻辑代码里面,交叉业务逻辑代码指的就是与主业务逻辑无关的代码,像事务、日志、缓存等。

在我们的项目中,使用传统的编码手段编写业务代码时,每一个功能的业务代码都极为繁琐,比如一个用户新增的业务,咱们得对它进行日志输出,对它的权限进行管理,同时还要对它进行事务管理,在这种情况下,咱们一个新增业务中,数十行代码里,新增的代码也就那么几行。况且咱们一个项目中不是只有一个新增的业务,还会用许多的业务功能,这样就导致编码人员不能全身心的将精力投放到主业务中。如下图所示。
在这里插入图片描述
为了改变这种局面,于是就有人想到了一个办法,将除去主业务的代码重新放到另外一个地方,在需要的时候再去调用这些代码。在这里就有了切面的概念,将方法注入到接口调用的某个地方(切点)。这样做的好处,不仅大大的减少了项目的代码量,还大大的增加了代码的可维护性与可读性,同时也能使编码人员在项目中能够将更多的精力放到主业务逻辑上。
在这里插入图片描述

什么是动态代理

动态代理就是在程序运行的时候,创建一个代理类,在代理类中创建一个代理对象,被代理的那个对象称之为目标对象,然后代理对象对目标对象中的方法进行功能性的增强。动态代理就是实现这个过程的一个技术。

代理类在程序运行期间创建的代理对象就称之为动态代理对象。在这种情况下呢,创建的代理对象,它不是java中已经定义好的,而是在运行的时候根据我们动态代理对象中的指示,动态生成的。也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象

动态代理的优势

动态代理在生成代理对象的过程中,目标是不变的,代理对象中的方法是目标对象方法的增强方法。可以理解为在运行期间,对象中方法进行动态拦截,并在拦截方法的前后执行功能操作,在这种情况下呢,可以让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情。

动态代理的实现

Aop动态代理的实现方式有两种,分别是基于JDK的动态代理和CGLIB的动态代理

基于JDK动态代理的实现

在基于JDK的动态代理的实现中有两个重要的接口和类:InvocationHandler, Proxy

InvocationHandler接口
是给代理实例的调用处理程序实现的接口。每个代理实例都会有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

Proxy类
JDK中用来生成代理对象的类。

定义一个例子的接口(interface )

package com.spring.proxy;

public interface Example {
    	
    	void hello(String name);

}

然后给这个接口定义一个实现类

package com.spring.proxy;

public class ExampleImpl implements Example {
    @Override
    public void hello(String name) {
        System.out.println("How are you recently "+name);
    }
}

在写好这个接口的实现类后,再来实现一个代理类,这个代理类必须实现InvocationHandler接口,代理类如下。

package com.spring.proxy;

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

public class JDKProxy implements InvocationHandler {
	//在代理类中定义一个对象
    private Object target;
	//给这个对象赋值
    public JDKProxy(Object target){
        this.target=target;
    }
    //创建代理
    public Object newProxy(){
       return Proxy.newProxyInstance(
       			//获取到target是由哪个类加载器来加载的
                target.getClass().getClassLoader(),
                //获取到动态生成的类的接口
                target.getClass().getInterfaces(),
                this
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        System.out.println("---------- 在业务方法调用之前可以进行前置增强   ------------");
		
		//利用反射机制调用方法
        Object nv = method.invoke(target, args);

        System.out.println("---------- 在业务方法调用之后可以进行前置增强   ------------");

        return nv;
    }
}

在完成代理类后,咱们写个简单的示例将方法调用一下。

package com.spring.proxy;

import com.sun.org.apache.bcel.internal.generic.NEW;

public class JDKProxyTest {
    public static void main(String[] args) {
		//获取到需要代理的对象
        Example example = new ExampleImpl();
		//获取带代理类,将需要代理的对象放进去
        JDKProxy jdkProxy = new JDKProxy(example);
		//获取到代理对象
        Example newProxy =(Example) jdkProxy.newProxy();
        newProxy.hello("王麻子");
    }
}

结果如下:
在这里插入图片描述


CGLIB的动态代理的实现

CGLIB是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate支持它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

实现cglib动态代理有一个核心的类Enhancer,具体实现过程与jdk的动态代理极为相似。

CGLIB动态代理示例

首先咱们先创建一个Maven项目,因为使用CGLIB动态代理需要导入cglib的依赖。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.1_3</version>
</dependency>

在导入完cglib的依赖后,我们再写一个例子类,在这个类中实现一个目标对象,这个类中不用实现任何接口,仅需要一个测试方法即可。

package com.spring.cglib;

public class Example {

    public void Hello(){
        System.out.println("Example : Hello");
    }
}

接下来咱们开始实现代理类,在实现代理类时需要继承cglib中的MethodInterceptor接口。

package com.spring.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class Proxy implements MethodInterceptor {
	 /**
     * obj:是cglib生成的代理对象
     * method:被代理的目标对象
     * args:给方法加入参数
     * proxy:代理方法
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
       
        System.out.println("----------在方法调用之前的----------");
        Object cb = proxy.invokeSuper(obj, args);
        System.out.println("----------在方法调用之后的---------");
       
        return cb;
    }
}

接下来咱们写一个Test 类来测试咱们的整个过程输出的结果。

package com.spring.cglib;

import net.sf.cglib.proxy.Enhancer;

public class Test {
    public static void main(String[] args) {

        // 通过CGLIB获取代理对象
        Enhancer enhancer = new Enhancer();
        //设置获取到的代理对象的父类
        enhancer.setSuperclass(Example.class);
        //设置代理对象的回调对象
        enhancer.setCallback(new Proxy());
        //创建代理对象
        Example pro =(Example) enhancer.create();
        //获取目标对象
        pro.Hello();
    }
}

输出结果如下
在这里插入图片描述


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值