Spring源码阅读(十一)—AOP补充

来源:互联网 发布:图片尺寸修改软件app 编辑:程序博客网 时间:2024/05/17 06:37

Spring源码阅读(十一)—AOP补充

AOP面向切面编程是面向对象编程的一种补充,广泛应用于事务,日志等场景;

AOP实现的关键在于AOP框架能够为目标类创建AOP代理,AOP代理根据创建的形式分为静态代理和动态代理;

静态代理是指在编译期间生成代理类,也成为编译时增强;动态代理是指运行期间借助JDK动态代理或者CGLIB等在内存中临时生成动态代理类,也称为运行时增强;

Spring AOP是运行时增强,AspectJ是编译时增强;Spring AOP为了简化配置使用了和AspectJ一样的注解,但是Spring AOP在运行是依旧是基于动态代理的运行时增强;

个人主页:tuzhenyu’s page
原文地址:Spring源码阅读(十一)—AOP补充

(1)JDK动态代理或CGLIB实现简单的AOP

JDK动态代理实现简单AOP通过定义被代理目标接口,目标实现类,实现了InvacationHandler接口的AOP逻辑实现类,通过Proxy类的newProxyInstance()方法动态生成代理类;

  • 代理目标接口
public interface ForumService {    public void addTopic();    public void removeTopic();}
  • 代理目标实现类
public class ForumServiceImpl implements ForumService {    public void addTopic(){        System.out.println("in the addTopic");    }    public void removeTopic(){        System.out.println("in the removeTopic");    }}
  • 代理横切织入代码
public class PerformanceHandler implements InvocationHandler{    private Object target;    public PerformanceHandler(Object target){        this.target = target;    }    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{        System.out.println("begin monitor...");        Object obj = method.invoke(target,args);        System.out.println("end monitor...");        return obj;    }}
  • 代理横测试类
public class Main {    public static void main(String[] args) {        ForumService target = new ForumServiceImpl();        PerformanceHandler handler = new PerformanceHandler(target);        ForumService proxy = (ForumService) Proxy.newProxyInstance(                target.getClass().getClassLoader(),                target.getClass().getInterfaces(),                handler        );        proxy.addTopic();        proxy.removeTopic();    }}

(2)通过ProxyFactory简化AOP的实现

为了简化AOP实现过程,可以使用ProxyFactory类,ProxyFactory类是对JDK动态代理和CGLIB动态代理的一个封装,将定义好的目标被代理类和增强Adviceh注入到ProxyFactory中生成代理类实现AOP功能;

  • 定义增强
public class UserBeforeAdvice implements MethodBeforeAdvice{    public void before(Method method, Object[] objects, Object o) throws Throwable {        System.out.println("before the method");    }}
  • 在XML配置文件中将增强和目标代理类注入到ProxyFactoryBean中
<?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:p="http://www.springframework.org/schema/p"       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/aop       http://www.springframework.org/schema/aop/spring-aop.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context.xsd">    <bean id="advice" class="aspectj.UserBeforeAdvice"></bean>    <bean id="target" class="aspectj.UserServiceImp"></bean>    <bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">        <property name="proxyInterfaces" value="aspectj.UserService"></property>        <property name="InterceptorNames" value="advice"></property>        <property name="target" value="target"></property>    </bean></beans>

(3)创建切点切面细化AOP操作

Spring通过切点定位到某些类的特定方法上,切点结合增强封装成切面用来具体实现AOP功能

  • 定义切面类,在切面类中通过ClassFilter和MethodMatcher进行切点匹配;切面是对切点和增强的封装;
public class UserAdvisor extends StaticMethodMatcherPointcutAdvisor {    public boolean matches(Method method, Class<?> aClass) {        return "addUser".equals(method.getName());    }}
  • 在XML配置文件中将增强注入到切面中
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean><bean id="advisor" class="aspectj.UserAdvisor">    <property name="advice" value="advice"></property></bean>
  • 在XML配置文件中将切面和目标代理类注入到ProxyFactoryBean中
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean><bean id="advisor" class="aspectj.UserAdvisor">    <property name="advice" value="advice"></property></bean><bean id="target" class="aspectj.UserService"></bean><bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">    <property name="proxyInterfaces" value="aspectj.Services"></property>    <property name="InterceptorNames" value="advisor"></property>    <property name="target" value="target"></property></bean>

(4) 通过自动创建代理简化AOP实现

使用ProxyFactoryBean实现AOP,每个需要被代理的Bean都需要使用一个ProxyFactoryBean进行配置;Spring提供了自动代理机制,底层使用BeanPostProcessor实现,在调动getBean()方法获取bean实例时会自动判断该类是否与切面匹配如果匹配则创建代理实例,否则创建普通实例;Spring的自动创建代理主要通过BeanNameAutoProxyCreator类,DefaultAdvisorAutoProxyCreator类,AnnocationAwareAspectjAutoProxyCreator类实现;

  • BeanNameAutoProxyCreator类:主要是为一组特定beanName的bean自动创建代理类,代理全部的方法;

  • DefaultAdvisorAutoProxyCreator类:扫描容器中的所有Advisor切面,自动将匹配的切面应用到Bean中;

  • AnnocationAwareAspectjAutoProxyCreator类:对AspectJ注解进行解析,扫描容器中的所有Advisor切面,自动将匹配的切面应用到Bean中;

  • 定义切面类,在切面类中通过ClassFilter和MethodMatcher进行切点匹配;切面是对切点和增强的封装;

public class UserAdvisor extends StaticMethodMatcherPointcutAdvisor {    public boolean matches(Method method, Class<?> aClass) {        return "addUser".equals(method.getName());    }}
  • 在XML配置文件中将增强注入到切面中
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean><bean id="advisor" class="aspectj.UserAdvisor">    <property name="advice" value="advice"></property></bean>
  • 定义DefaultAdvisorAutoProxyCreator实例,自动扫描容器内的切面,并在调用getBean()是判断是否匹配,如果匹配则创建相应的代理类;
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean><bean id="advisor" class="aspectj.UserAdvisor">    <property name="advice" value="advice"></property></bean><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean><bean id="userService" class="aspectj.UserService"></bean>

(5) 通过AspectJ注解进一步简化AOP配置

  • 利用@Aspect定义切面类,将增强和切点结合在切面类中
@Aspect@Compentpublic class UserAdvisor {   @Before("execution(* addUser(...))")   public void before(){       System.out.println("in the before");   }}
  • 定义AnnocationAwareAspectjAutoProxyCreator实例开启AspectJ注解模式,自动扫描容器内的切面,并在调用getBean()是判断是否匹配,如果匹配则创建相应的代理类;
<bean class="org.springframework.aop.framework.autoproxy.AnnocationAwareAspectjAutoProxyCreator"></bean>

如果使用了aop命名空间则使用aop标签定义

<aop:aspectj-autoproxy>

总结

  • Spring AOP主要是由sping-aop和sping-aspects组成;

  • AOP是一种面向切面编程的思想,是对面向对象的一种补充,在日志以及事务管理等方面有着较多的应用;

  • AOP实现的关键在于AOP框架能够为目标类创建AOP代理,AOP代理根据创建的形式分为静态代理和动态代理;静态代理是指子啊编译期生成代理类,动态代理是指在运行期间在内存中生成临时代理类;Spring AOP是动态代理,AspectJ是静态代理,虽然Spring引入Aspects包支持AspecJ注解等,但是底层代理实现仍然是通过动态代理;

  • Spring AOP实现

    • 可以通过JDK动态代理或者CGLIB动态代理直接实现,以JDK动态代理为例,定义目标接口,被代理目标类和实现了AOP逻辑的实现了InnovocationHandler的处理类,调用Proxy类的newProxyInstance()方法生成代理类;

    • 为了简化配置可以使用ProxyFactoryBean,将切点或切面,被代理目标类注入ProxyFactoryBean中生成代理类;

    • 为了进一步简化配置,可以定义自动创建类autoProxyCreator,会在bean实例创建时,搜索容器内的切面,如果匹配则生成代理类实例,如果不匹配则生成普通实例;

    • 为了进一步简化配置,使用AspectJ注解,在切面类上使用@Aspect注解,在容器初始化时会将该切面类加载到容器中,在bean实例创建时,搜索容器内的切面,如果匹配则生成代理类实例,如果不匹配则生成普通实例