上一篇聊到关于spring
1、自定义注解
2、springAOP切面
3、各种连接点joinPoint的意义
4、spring的JDK代理,与产生的一些问题
接上篇,继续讲解SpringAOP通知。其他通知都比较简单,大家可以参考官方文档。这里只讲解一个比较难得环绕通知!
1、spring通知
1、前置通知,证明springAOP默认是使用JDK动态代理。
如下代码片段,可以通过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引入的新特性)
话不多说,上代码片段。领略神奇之处。(面试中可能会被问到,怎么克隆一个类的方法)
项目结构如下
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();
}
}
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);
}
}