beizili

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Spring Aop原理解析和使用示例

前言

众所周知,Spring拥有两大特性:IoC和AOP。IoC,英文全称Inversion of Control,意为控制反转。AOP,英文全称Aspect-Oriented Programming,意为面向切面编程。

今天我们的主题就是Spring的Aop的源码解析。

Spring Aop相关概念

Spring Aop基本原理

Spring Aop的实现的原理就是JDK的动态代理。核心思想就是利用动态代理模式,再方法执行前后或者出现异常时加入相关逻辑。

JDK动态代理入门

利用java的反射机制,使用Proxy.newProxyInstance创建代理类对象,从而代理目标对象的调用。

**目的:**在完成目标对象调用时,进行功能增强。

**大致实现:**使用反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Proxy。

Proxy.newProxyInstance:静态方法,用于创建代理对象。参数列表如下:

  • ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader类a, a.getCalss().getClassLoader(), 目标对象的类加载器。
  • Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
  • InvocationHandler h : 我们自己写的,代理类要完成的功能。

InvocationHandler:接口类,实现目标对象的代理调用。接口方法如下:

  • public Object invoke(Object proxy, Method method, Object[] args){}
    • Object proxy: jdk创建的代理对象,无需赋值。
    • Method method: 目标类中的方法,jdk提供method对象的。
    • Object[] args: 目标类中方法的参数, jdk提供的。

动态代理举例

ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader类a, a.getCalss().getClassLoader(), 目标对象的类加载器
Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
InvocationHandler h : 我们自己写的,代理类要完成的功能。

InvocationHandler:接口类,实现目标对象的代理调用

动态代理举例

/**
 * 接口类
 */
public interface IHelloWorld {
    void publicSayHello();
}
/**
 * 实现类
 */
public class HelloWorld implements IHelloWorld {
    private void privateSayHello() {
        System.out.println("private:hello world");
    }

    /**
     * 接口实现方法
     */
    public void publicSayHello() {
        System.out.println("public:hello world");
    }
}
/**
 * 自定义动态代理
 */
public class MyInvocationHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("start.");
        Object obj = method.invoke(target, args);
        System.out.println("end.");
        return obj;
    }

    /**
     * 获取动态代理对象
     * @return 代理对象
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}
/**
 * 测试类
 */
public class ProxyTest {
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(helloWorld);
        Object object = myInvocationHandler.getProxy();
        IHelloWorld object1 = (IHelloWorld)object;
        object1.publicSayHello();
    }
}

输出如下:

start.
public:hello world
end.

Spring Aop代码实现原理

Spring Aop的代码实现逻辑是嵌入在Spring Bean的生成过程中的。

  1. Spring Bean的生成过程是什么样的?

    Spring Bean的生成过程大致可以总结为"实例化" ==> “依赖注入” ==> “回调(Aware回调)” ==> “初始化” ==> BeanPostProcessor

  2. Spring Aop的能力是利用Spring Bean生成过程中的BeanPostProcessor,对生成的实例进行动态代理的后置处理,使得Spring Bean生成后,拿到的是经过Spring动态代理之后的代理对象

代码示例:

// bean生命周期
// 实例化 -> 依赖注入 -> 回调(Aware回调) -> 初始化 -> AOP
private Object createBean(String beanName, BeanDefinition beanDefinition) {
    Class clazz = beanDefinition.getType();
    try {
        Object instance = clazz.getConstructor().newInstance();
        // 依赖注入
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            if (f.isAnnotationPresent(Autowired.class)) {
                f.setAccessible(true);
                Object value = getBean(f.getName());
                f.set(instance, value);
            }
        }

        // 回调
        if (instance instanceof BeanNameAware) {
            ((BeanNameAware) instance).setBeanName(beanName);
        }

        // AOP BeanPostProcessor机制
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
            instance = beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
        }

        // 初始化
        if (instance instanceof InitializingBean) {
            ((InitializingBean) instance).afterPropertiesSet();
        }

        // AOP BeanPostProcessor机制
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
            instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
        }

        return instance;
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    return null;
}

Spring BeanProcess接口:

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(String beanName, Object bean);
    Object postProcessAfterInitialization(String beanName, Object bean);
}

Spring Aop使用示例

基于配置文件的使用示例

 <bean id="agentAdvisorXML" class="com.fufu.spring.aop.AgentAdvisorXML"/>
<!--Spring基于Xml的切面-->
     <aop:config>
         <!-- 定义切点函数 -->
         <aop:pointcut id="singPointCut" expression="execution(* com.test.proxy.User.sing(..))"/>
         <!-- 定义切面 order 定义优先级,值越小优先级越大-->
         <aop:aspect ref="agentAdvisorXML" order="0">
             <!--前置通知-->
             <aop:before method="getMoney" pointcut-ref="singPointCut"/>
             <!--后置通知-->
             <aop:after method="writeReceipt" pointcut-ref="singPointCut"/>
         </aop:aspect>
     </aop:config>

基于注解的使用示例

  1. 开启@AspectJ注解支持

    <aop:aspectj-autoproxy/>
    
  2. 在类的相应位置加上注解

    	 /**
    	 * Created by zhoujunfu on 2018/9/7.
    	 * 基于注解的Spring AOP
    	 */
    	@Aspect
    	@Component
    	public class AgentAdvisor {
    	 
    	    @Before(value = "execution(* com.fufu.proxy.ShowService.sing(..))")
    	    public void getMoney() {
    	        System.out.println("get money");
    	    }
    	 
    	    @After(value = "execution(* com.fufu.proxy.ShowService.sing(..))")
    	    public void writeReceipt() {
    	        System.out.println("write receipt");
    	    }
    	}
    

    手撸Spring源码,精简易懂:https://download.csdn.net/download/jjs15259655776/85816604

posted on 2022-06-28 23:49  被子里  阅读(44)  评论(0编辑  收藏  举报  来源