首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动手实现AOP

动手实现AOP

作者头像
每天学Java
发布2020-06-02 10:07:18
2700
发布2020-06-02 10:07:18
举报
文章被收录于专栏:每天学Java每天学Java每天学Java

在前面的两篇文章中,我们了解了Spring AOP的应用以及两种动态代理的实现,但是如何实现AOP我想小伙伴应该会很疑惑,所以今天我们自己来动手撸代码简单的实现一下AOP。

先说一说我对Spring AOP的理解:在Spring应用启动的时候,Spring框架会将配置文件或者注解下的对象注入到工厂类中,当相应的对象被引用的时候,我们通过方法拦截器链进行拦截判断,如果该对象存在AOP的相关配置(拦截范围内),那么我们就返回其增强的代理对象,否则返回其本身的实例。有过Spring项目的小伙伴应该都知道Autowired注解,它帮助我们完成自动装配的工作,而在我写完前面两篇文章的时候,我就在想如何实现自动装配并且返回一个代理对象。下面我们具体来看看如何实现。

相关文章:

解读Java 注解 (Annotation)

动态代理技术的运用

Spring AOP的简单应用

01

首先我们定义一个对象。

package com.example.demo.aop.test;

/**
 * @Auther: chenlong
 * @Date: 2019/3/15 14:37
 * @Description:
 */
public class TestAPIImp  {

    public void test() {
        System.out.println("测试数据");
    }
}

定义一个注解,我们规定被这个注解修饰的对象使用自动装配,而不用自己去new对象。对于注解不是很熟悉的小伙伴可以先看相关文章:解读Java 注解

package com.example.demo.aop.test;

import java.lang.annotation.*;

/**
 * @Auther: chenlong
 * @Date: 2019/3/15 14:55
 * @Description:
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD,ElementType.FIELD})
@Documented
@Inherited
public @interface Demo {
}

我们在定义一个类似与Controller的类,这里大家可以看一下,我们并没有去new它,直接调用其方法,核心在于init()方法将对象进行了装配,其中存在Demo的注解我们使用动态代理增加一些日志,而testAPIImp2我们返回其实例。

public class MyProxy {

    @Demo
    public static TestAPIImp testAPIImp;

    public static TestAPIImp testAPIImp2;

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        init();
        //被代理
        testAPIImp.test();
        //不被代理
        testAPIImp2.test();
    }
}

在具体分析之前我们看一下效果:这里的执行前和执行后就是使用CGLib动态代理的效果。

具体实现我们来一步一步看,首先我们看一下CGLib,其核心就是为了在方法执行前后打印日志

package com.example.demo.aop.cglib;

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

import java.lang.reflect.Method;

/**
 * @Auther: chenlong
 * @Date: 2019/3/9 21:42
 * @Description:
 */
public class CGLIBProxy implements MethodInterceptor {


    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行前...");
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("执行后...");
        return object;
    }

}

然后我们再看init()方法通过getClasses方法(该方法在小程序的代码库中有详细代码,可自行去复制)获取到com.example.demo.aop.test目录下的class对象,如何对象名称为MyProxy我们就开始对字段进行遍历和赋值(实际上这一步也可以用自定义注解实现,如果遍历的class有我们自定义的注解,我们再遍历其字段,而不是定死为MyProxy),如果Field对象通过set方法可以进行赋值(详细的这里就不描述了),我们可以看到如果field.getAnnotation(Demo.class)!=null也就是说该字段被注解修饰我们就是就将代理对象set进去,否则set自己的实例对象。

    public static void init() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Set<Class<?>> set = new MyProxy().getClasses("com.example.demo.aop.test");
        for (Class<?> class1 : set) {
            if (class1.getSimpleName().equals("MyProxy")) {
                Field[] fields = class1.getFields();
                for (final Field field : fields) {
                        try {
                            for (final Class<?> class2 : set) {
                                if (class2.getSimpleName().equals(field.getType().getSimpleName())) {
                                    if (field.getAnnotation(Demo.class)!=null) {
                                    Enhancer enhancer = new Enhancer();
                                    enhancer.setSuperclass(class2);
                                    enhancer.setCallback(new CGLIBProxy());
                                    Object o = enhancer.create();
                                    field.set(class1.newInstance(), o);
                                    }else {
                                    field.set(class1.newInstance(), field.getType().newInstance());
                                    }
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }


                }
            }
        }
    }

到这里就简单的实现了自己理解下的AOP,实际上我们还可以继续优化,比如说自己写工厂类,将对象都注入到该工厂中,同时通过CGLib我们也可以实现方法的拦截器链,跟拦截器相关的还是适配器模式的相关应用。在后续我也将按照这个方向来进行相关文章的开展,今天我们就说到这里。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云微搭低代码
微搭低代码是一个高性能的低代码开发平台,用户可通过拖拽式开发,可视化配置构建 PC Web、H5 和小程序应用。 支持打通企业内部数据,轻松实现企业微信管理、工作流、消息推送、用户权限等能力,实现企业内部系统管理。 连接微信生态,和微信支付、腾讯会议,腾讯文档等腾讯 SaaS 产品深度打通,支持原生小程序,助力企业内外部运营协同和营销管理。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档