深入理解Spring(AOP)(四)

上一篇聊到关于spring
1、自定义注解
2、springAOP切面
3、各种连接点joinPoint的意义
4、spring的JDK代理,与产生的一些问题
接上篇,继续讲解SpringAOP通知。其他通知都比较简单,大家可以参考官方文档。这里只讲解一个比较难得环绕通知!

1、spring通知

1、前置通知,证明springAOP默认是使用JDK动态代理。

深入理解Spring(AOP)(四)_第1张图片

如下代码片段,可以通过joinPoint对象,获取目标对象。以及代理对象,还能获取方法传入的参数。实际业务开发中。可以对目标对象,与参数做一些业务处理。

(面试问题)joinPoint是什么?它是AOP中的连接点,可以通过它得到。类信息,代理对象信息,方法信息,参数信息。常用的API见下面代码片段:

    /**
     * 申明before通知,在pintCut切入点前执行
     * 通知与切入点表达式相关联,
     * 并在切入点匹配的方法执行之前、之后或前后运行。
     * 切入点表达式可以是对指定切入点的简单引用,也可以是在适当位置声明的切入点表达式。
     */
    @Before("pointCut()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("before");
        //获取当前执行的代理对象
        System.out.println(joinPoint.getThis());
        //获取目标对象
        System.out.println(joinPoint.getTarget());
        //获取当前传入参数
        Object[] args = joinPoint.getArgs();
        System.out.println(args);
        //获取切点的目标方法
        String name = joinPoint.getSignature().getName();
        System.out.println(name);
    }
2、环绕通知

环绕通知部分代码如下。文章示例,可用于项目中改变连接参数值。控制台输出


    @Override
    public void query(String str) {
        System.out.println("query2 " + str);
    }
/*   * 增强通知(也叫环绕通知)
       Proceedingjoinpoint 和JoinPoint的区别:
       Proceedingjoinpoint 继承了JoinPoint,proceed()这个是aop代理链执行的方法。并扩充实现了proceed()方法,
       用于继续执行连接点。JoinPoint仅能获取相关参数,无法执行连接点。
        proceed()有重载,有个带参数的方法,可以修改目标方法的的参数
     * @param pjp 用于描述切点的所有连接点(这里很抽象,就是描述所有需要增强方法的信息)
     */
    @Around("execution(* com.bing.dao.IndexDao.query(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("aaaaa");
        Object[] args = pjp.getArgs();
        for (int i = 0; i < args.length; i++) {
            args[i]+="world";
        }
        //处理下一个通知,或者目标方法的执行。就是这个方法实现了环绕
        //最牛逼之处,这个方法重载参数。可以改变目标方法的一些参数信息
        pjp.proceed(args);
        System.out.println("bbbbbb");
    }
3.@DeclareParents注解引入(spring5 AOP引入的新特性)

话不多说,上代码片段。领略神奇之处。(面试中可能会被问到,怎么克隆一个类的方法)

项目结构如下

深入理解Spring(AOP)(四)_第2张图片
1.在spring切面中引入要申明的Dao类型
2.声明一个类交给spring管理,不实现任何借口。
3.获取声明类,强转成Dao类型。(正常情况下这里肯定会报错吧,因为Order并没有实现Dao接口)
4.然而我们执行query方法,控制台输出Query11 说明 springAOP 去帮我们实现Dao 帮我们继承了 indexDao这个类。

@Component
@Aspect
public class UserAspectj {
    /**
     * 引入 dao
     */
    @DeclareParents(value = "com.bing.dao.*",defaultImpl = IndexDao.class)
    public static Dao dao;
    }
    //声明一个类交给Spring管理
@Component("orderDao")
public class OrderDao {
			}
	//获取声明类,强转成Dao类型
public class Test {
    public static void main(String[] args) throws IOException {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(Appconfig.class);
        Dao dao = (Dao) applicationContext.getBean("orderDao");
        dao.query();
        	}
        }

深入理解Spring(AOP)(四)_第3张图片

4.切面如何多例。下面看一个例子。。当我们并发编程,一般会用多例模式,但是我们切面始终都是单例。。

1.将IndexDao设置为多例模式
2.定义切换,打印当前切面类的hashCode
3.执行多例对象 方法,发现。输出的切面类hashcode始终都是同一个(说明切面类是单例。)

怎么解决这个问题呢?(面试官:切面模型怎么变成多例?)

@Repository(value = "indexDao")
@Scope("prototype")
public class IndexDao implements Dao{
    @Override
    public void query(){
        System.out.println("Query11");
    }
    @Override
    public void query(String str) {
        System.out.println("query2 " + str);
    }
}

深入理解Spring(AOP)(四)_第4张图片
深入理解Spring(AOP)(四)_第5张图片

解决方案:perthis定义哪个类执行该切面时当前类变成多例,若不定义perthis则所以类执行时都会变成多例 。perthis限定某一个对象。

深入理解Spring(AOP)(四)_第6张图片

Advisors ? 什么是Advisors ?

Advisors 又叫spring声明式事务,或者AOP事务,很多人理解,AOP就是事务。。这种说法是错误的,Spring事务,只是借助了AOP的技术去实现。。并不是真正意义上的AOP。为什么这么说呢?

我们到这里已经学完了,SpringAOP 所有内容,可以发现,AOP 的通知类型,要么是在方法执行前执行,要么是在方法执行后 执行。要么方法执行前跟后一起执行。。却没有一种通知,可以在方法中执行。都知道事务在做增删改时候,会提交事务,回滚事务。所以可以说Spring声明式事务,是一个特殊的通知。但是它并不在我们AOP 的内容中(可以从官方文档发现)

@transactional 是Spring基于Aspect技术开发的事务控制注解,并不是Aspect的注解。(这里是一个很多高级开发的误区

你可能感兴趣的:(spring源码学习,互联网工程)