查看原文
其他

【334期】面试官问:Spring Aop 与 AspectJ 有什么区别和联系?

Java精选 2022-08-09

区别

AspectJ

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

spring aop

Spring提供了四种类型的Aop支持

  • 基于经典的SpringAOP

  • 纯POJO切面

  • @ASpectJ注解驱动的切面

  • 注入式AspectJ切面(其实与Spring并无多大的关系,这个就是使用AspectJ这个框架实现Aop编程)

基于经典的SpringAop

其使用ProxyFactoryBean创建。另外,这篇文章详细描述了Spring AOP、AspectJ、CGLIB ?它们有什么关系?

增强(通知)的类型有:

  • 前置通知:org.springframework.aop.MethodBeforeAdvice

  • 后置通知:org.springframework.aop.AfterReturningAdvice

  • 环绕通知:org.aopalliance.intercept.MethodInterceptor

  • 异常通知:org.springframework.aop.ThrowsAdvice

public interface IBookDao {
    public int add()
    public int delete()
;
}
 
public class BookDaoImpl implements IBookDao{
    public int add() {
        System.out.println("正在添加图书...");
        return 0;
    }
    public int delete() {
        System.out.println("正在删除图书...");
        return 0;
    }
}
 
//实现了MethodInterceptor的环绕增强类
public class MyAdvice implements MethodInterceptor{
 
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("Around Advice before method invocation");
        Object o = invocation.proceed();
        System.out.println("Around Advice after method invocation");
        return o;
    }
}

将每一个连接点都当做切点(拦截每一个方法)

<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
 
    <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>
 
    <bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="bookDao"/>
        <property name="proxyInterfaces" value="com.njust.learning.spring.service.IBookDao"/>
        <property name="interceptorNames" value="myadvice"/>
</bean>

使用RegexMethodPointcutAdvisor针对某些特定的方法进行拦截增强

<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>

   <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>


   <bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
       <!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"-->
       <property name="patterns" value=".*add"/>
       <property name="advice" ref="myadvice"/>
   </bean>
<!--使用的时候使用这个id,而不是原始的那个id-->
   <bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
       <property name="target" ref="bookDao"/>
       <property name="proxyInterfaces" value="com.njust.learning.spring.service.IBookDao"/>
       <property name="interceptorNames" value="rmpAdvisor"/>
   </bean>

注意:

像上面这样,每定义一个dao都需要定义一个ProxyFactoryBean,显得很麻烦,所以我们引入自动代理,也就是自动创建代理对象。

另外,推荐下 Spring boot 的用户权限管理系统开源项目:

https://gitee.com/yoodb/jing-xuan

BeanNameAutoProxyCreator
<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
 
    <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>
 
    <bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"-->
        <property name="patterns" value=".*add"/>
        <property name="advice" ref="myadvice"/>
    </bean>
 
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Dao"></property>
        <property name="interceptorNames" value="rmpAdvisor"></property>
    </bean>
DefaultAdvisorAutoProxyCreator
<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
 
    <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>
 
    <bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"-->
        <property name="patterns" value=".*add"/>
        <property name="advice" ref="myadvice"/>
    </bean>
 
    <!--根据切面中生成信息生成代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
纯POJO切面,需要使用XML进行配置
public interface IBookDao {
    public int add();
    public int delete();
}
 
public class BookDaoImpl implements IBookDao{
 
    public int add() {
        int a = 1/0;
        System.out.println("正在添加图书...");
        return 0;
    }
 
    public int delete() {
        System.out.println("正在删除图书...");
        return 0;
    }
}
public class PojoAdvice {
    public void before(){
        System.out.println("前置通知");
    }
    public void after(Object returnval){
        System.out.println("后置通知"+",处理后的结果为:"+returnval);
    }
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前置增强...");
        Object o = proceedingJoinPoint.proceed();
        System.out.println("环绕后置增强...");
        return o;
    }
    public void afterThrowing(Throwable e){
        System.out.println("异常通知:"+e.getMessage());
    }
}
<bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
 
    <bean id="pojoAdvice" class="com.njust.learning.spring.pojoaop.PojoAdvice"></bean>
 
    <aop:config>
        <aop:pointcut id="p" expression="execution (* *.add(..))"/>
        <aop:aspect ref="pojoAdvice">
            <aop:before method="before" pointcut-ref="p"></aop:before>
            <!--通过设置returning来将返回值传递给通知-->
            <aop:after-returning method="after" pointcut-ref="p" returning="returnval"/>
            <aop:around method="around" pointcut-ref="p"/>
            <!--通过设置returning来将异常对象传递给通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="p" throwing="e"/>
        </aop:aspect>
    </aop:config>

联系

我们借助于Spring Aop的命名空间可以将纯POJO转换为切面,实际上这些POJO只是提供了满足切点的条件时所需要调用的方法,但是,这种技术需要XML进行配置,不能支持注解。另外,关于Spring面试题,公众号Java精选,回复java面试,获取spring面试资料。

所以spring借鉴了AspectJ的切面,以提供注解驱动的AOP,本质上它依然是Spring基于代理的AOP,只是编程模型与AspectJ完全一致,这种风格的好处就是不需要使用XML进行配置。

使用@Aspect方式,你就可以在类上直接一个@Aspect就搞定,不用费事在xml里配了。但是这需要额外的jar包(aspectjweaver.jar)。因为spring直接使用AspectJ的注解功能,注意只是使用了它 的注解功能而已,并不是核心功能 。

SpringAop的底层技术依然是Jdk动态代理和Cglib。

作者:ready? go!

https://blog.csdn.net/flyfeifei66/article/details/82784321

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

最近有很多人问,有没有读者交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!

(微信小程序):3000+道面试题,包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计等,在线随时刷题!

------ 特别推荐 ------

特别推荐:专注分享最前沿的技术与资讯,为弯道超车做好准备及各种开源项目与高效率软件的公众号,「大咖笔记」,专注挖掘好东西,非常值得大家关注。点击下方公众号卡片关注

文章有帮助的话,在看,转发吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存