自己动手写一个spring之aop_1

写在前面

本文看下如何实现AOP相关内容。

1:为什么需要AOP

工作中有很多非主业务相关,但又必不可少的内容,比如日志打印,权限校验,事务处理,性能监控等。这些准确来说都是属于一些边缘的例行性代码,这些代码固定写死到程序中显然是不合适的,所以我们就需要AOP来动态的帮我们添加这些内容。

2:正文

正常通过getBean方法获取的就是配置的bean,那么想要实现AOP,其实也很简单,只需要在getBean时返回一个代理对象就可以了,具体该怎么做呢?可以这样子,首先定义一个接口,如果配置的bean该接口类型的,则不直接返回其作为最终bean,而是进一步的调用其内部方法获取最终bean,这个最终bean就是代理bean,定义接口如下:

java 复制代码
/**
 * 提供给用户返回自定义对象作为bean的接口,可以认为是一个为bean定制化预留的接口
 * @param <T>
 */
public interface FactoryBean<T> {
    T getObject() throws Exception;

    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }

}

其中方法getObject就是用来获取真正的目标bean,这里我们可以返回一个代理对象实现AOP。给出实现类:

java 复制代码
public class ProxyFactoryBean implements FactoryBean<Object> {
    // ...

    @Override
    public Object getObject() throws Exception {
        return getSingletonInstance();
    }

    private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            this.singletonInstance = getProxy(createAopProxy());
        }
        System.out.println("----------返回代理类 :" + this.singletonInstance + "--------" + this.singletonInstance.getClass());

        return this.singletonInstance;
    }

    protected Object getProxy(AopProxy aopProxy) {
        return aopProxy.getProxy();
    }
    
}

为了支持获取不同的代理类,定义接口AopProxy,如下:

java 复制代码
/**
 * 代理类接口,支持返回不同类型的代理类(jdk动态代理,基于asm的代理类等)
 */
public interface AopProxy {
	Object getProxy();
}

实现类:

java 复制代码
package com.hc.minispring.aop;

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

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
    Object target;

    public JdkDynamicAopProxy(Object target) {
        this.target = target;
    }


    @Override
    public Object getProxy() {
        Object obj = Proxy.newProxyInstance(JdkDynamicAopProxy.class.getClassLoader(), target.getClass().getInterfaces(), this);
        System.out.println("----------创建基于jdk的动态代理类成功: ---------" + obj);
        return obj;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("doAction")) {
            System.out.println("-----通过jdk动态代理,代理了类的doAction方法........");
            return method.invoke(target, args);
        }
        return null;

    }
}

是基于jdk的动态代理。为了方便获取AopProxy创建工厂类:

java 复制代码
/**
 * 代理类创建对象的工厂类,方便对象创建
 */
public interface AopProxyFactory {
	AopProxy createAopProxy(Object target);

}

实现类:

java 复制代码
package com.hc.minispring.aop;

/**
 * 默认代理类工厂,返回基于jdk的动态代理类
 */
public class DefaultAopProxyFactory implements AopProxyFactory {

    @Override
    public AopProxy createAopProxy(Object target) {
        return new JdkDynamicAopProxy(target);
    }
}

因为增加了一种获取bean的方式,即基于factorybean的getObject方法,所以我们需要增加新的bean工厂类来支持这种方式,如下:

java 复制代码
package com.hc.minispring.aop;

import com.hc.minispring.ioc.four_beanfactory_and_event.beans.factory.BeansException;
import com.hc.minispring.ioc.four_beanfactory_and_event.beans.factory.support.DefaultSingletonBeanRegistry;

/**
 * 支持获取工厂bean的类,真正获取bean的逻辑由FactoryBean类的实现类提供(用户动态提供,或使用框架已经给出的默认扩展)
 */
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

    protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
        return factoryBean.getObjectType();
    }

    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        try {
            object = postProcessObjectFromFactoryBean(object, beanName);
        } catch (BeansException e) {
            e.printStackTrace();
        }
        return object;
    }

    private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) {

        Object object = null;
        try {
            object = factory.getObject();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return object;
    }

    protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
        return object;
    }

    protected FactoryBean<?> getFactoryBean(String beanName, Object beanInstance) throws BeansException {
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeansException(
                    "Bean instance of type [" + beanInstance.getClass() + "] is not a FactoryBean");
        }
        return (FactoryBean<?>) beanInstance;
    }
}

接着修改abstractbeanfactory:

java 复制代码
//public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory, BeanDefinitionRegistry {
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements BeanFactory, BeanDefinitionRegistry {
    // ...

    public Object getBean(String beanName) throws BeansException {
        Object singleton = this.getSingleton(beanName);
        
        // ...
        
        // 支持FacotryBean
        if (singleton instanceof FactoryBean) {
            System.out.println("发现工厂bean ,尝试从工厂bean获取用户自定义bean-------------- " + beanName + "----------------"+singleton);
            return this.getObjectForBeanInstance(singleton, beanName);
        } else {
            System.out.println("普通的bean,直接从ioc容器中拿到的就是:-------------- " + beanName + "----------------"+singleton);
        }
        return singleton;
    }
}

3:测试

定义测试接口:

java 复制代码
public interface IAction {
	void doAction();
}

实现类:

java 复制代码
public class Action1 implements IAction {

    @Override
    public void doAction() {
        System.out.println("really do action");
    }

}

controller:

java 复制代码
package com.hc.minispring.web.v7_aop.controller;

public class HelloController {

    @Autowired
    private IAction action;

    @RequestMapping("/hello1746")

    public String doTest(/*HttpServletRequest request, HttpServletResponse response*/) {

        System.out.println("action: " + action.getClass());

        action.doAction();

        return "index";
    }

}

applicationContext.xml:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="realaction" class="com.hc.minispring.web.v7_aop.Action1" />
    <bean id="action" class="com.hc.minispring.aop.ProxyFactoryBean" >
        <property type="java.lang.Object" name="target" ref="realaction"/>
    </bean>


    <bean id="webBindingInitializer" class="com.hc.minispring.web.v5_databind.DateInitializer"></bean>
    <!-- ... -->
</beans>

运行:

源码

写在后面

参考文章列表

相关推荐
__zRainy__6 小时前
Node系列 · Node基础:net 模块
后端·node.js
Diligently_6 小时前
Anolis 系统更新与密码设置&磁盘扩容
java·后端·spring
kyson_6 小时前
大文件切片上传:从“能传”到“可靠”的 Vue 3 + Java 全栈实现
后端
张龙6876 小时前
uv 全面指南:比 pip 快 100 倍的 Python 包管理器,从安装到团队落地
后端·python
mqiqe7 小时前
线程调度与 Schedulers:Project Reactor 并发模型的核心引擎
java·开发语言·网络
我命由我123457 小时前
Android 开发问题:unexpected element <service> found in <manifest>
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
正在走向自律7 小时前
飞算JavaAI能搞定充电站故障处置吗?
java·ai编程·java开发·飞算javaai·java代码生成·ai coding模型·springboo
用户40966601317517 小时前
Guava 不止有 Lists 和 Maps:Cache、EventBus、Multimap 实战
java·后端