1.问题描述
目标对象内部的函数自我调用时被调函数将忽略切面。
1)实例
SelfInvokable.java
public interface SelfInvokable { void invoke(); void method(); }
SelfInvoker.java
public class SelfInvoker implements SelfInvokable { public void invoke() { System.out.println("in SelfInvoker.invoke..."); } public void method() { System.out.println("in SelfInvoker.method..."); this.invoke(); } }
SelfInvoker2.java
public class SelfInvoker2 { public void invoke() { System.out.println("in SelfInvoker2.invoke..."); } public void method() { System.out.println("in SelfInvoker2.method..."); this.invoke(); } }
spring-aop.xml
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="selfInvoker" class="com.siyuan.study.spring.aop.SelfInvoker"/> <bean id="selfInvoker2" class="com.siyuan.study.spring.aop.SelfInvoker2"/> <bean id="beforeAdvisor" class="com.siyuan.study.spring.aop.advisor.BeforeAdvisor"/> <aop:config> <aop:pointcut id="selfInvokerPointcut" expression="execution(* com.siyuan.study.spring.aop.*.*(..))" /> <aop:advisor advice-ref="beforeAdvisor" pointcut-ref="selfInvokerPointcut"/> </aop:config> </beans>
SelfInvokerAOPTest.java
public class SelfInvokerAOPTest { private ApplicationContext ctxt; @Before public void setup() { ctxt = new ClassPathXmlApplicationContext("spring-aop.xml"); } @Test public void testSelfInvokable() { SelfInvokable selfInvoker = (SelfInvokable) ctxt.getBean("selfInvoker"); System.out.println("JDK proxy : " + AopUtils.isJdkDynamicProxy(selfInvoker)); selfInvoker.invoke(); selfInvoker.method(); } @Test public void testSelfInvokable2() { SelfInvoker2 selfInvoker2 = (SelfInvoker2) ctxt.getBean("selfInvoker2"); System.out.println("CGLIB proxy : " + AopUtils.isCglibProxy(selfInvoker2)); selfInvoker2.invoke(); selfInvoker2.method(); } }
执行结果:
JDK proxy : true before invoke in SelfInvoker.invoke... before method in SelfInvoker.method... in SelfInvoker.invoke... CGLIB proxy : true before invoke in SelfInvoker2.invoke... before method in SelfInvoker2.method... in SelfInvoker2.invoke...
2)分析:
Spring AOP实现代理有两种方式
--JDK:目标对象有实现接口时,仅对目标对象实现接口中的方法进行拦截,接口中未包含的方法将不进行拦截。
--CGLIB:目标对象未实现任何接口时。
从执行结果来可看出,两种不同方式获得的代理在函数自我调用时被调用函数均忽略了切面。
2.修复
1)AopContext获取代理对象,实现原理ThreadLocal
SelfInvokable.java
public interface SelfInvokable { ... void methodFix(); }
SelfInvoker.java
public class SelfInvoker implements SelfInvokable { ... public void methodFix() { System.out.println("in SelfInvoker.methodFix..."); ((SelfInvokable) AopContext.currentProxy()).invoke(); } }
SelfInvoker2.java
public class SelfInvoker2 { ... public void methodFix() { System.out.println("in SelfInvoker2.methodFix..."); ((SelfInvoker2) AopContext.currentProxy()).invoke(); } }
spring-aop.xml
... <aop:config expose-proxy="true"> ...
SelfInvokerAOPTest.java
@Test public void testSelfInvokable() { ... selfInvoker.methodFix(); } @Test public void testSelfInvokable2() { ... selfInvoker2.methodFix(); }
执行结果
JDK proxy : true before invoke in SelfInvoker.invoke... before method in SelfInvoker.method... in SelfInvoker.invoke... before methodFix in SelfInvoker.methodFix... before invoke in SelfInvoker.invoke... CGLIB proxy : true before invoke in SelfInvoker2.invoke... before method in SelfInvoker2.method... in SelfInvoker2.invoke... before methodFix in SelfInvoker2.methodFix... before invoke in SelfInvoker2.invoke...
2)BeanPostProcessor+BeanSelfAware(标记需要自调用的接口)
BeanSelfAware.java
public interface BeanSelfAware { void setSelf(Object self); }
SelfInvoker.java
... public void methodFix() { System.out.println("in SelfInvoker.methodFix..."); //((SelfInvokable) AopContext.currentProxy()).invoke(); self.invoke(); } private SelfInvokable self; public void setSelf(Object self) { this.self = (SelfInvokable) self; } ...
InjectBeanSelfProcessor.java
public class InjectBeanSelfProcessor implements BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof BeanSelfAware) { BeanSelfAware myBean = (BeanSelfAware)bean; myBean.setSelf(bean); return myBean; } return bean; } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } }
spring-aop.xml
... <bean class="com.siyuan.study.spring.extension.InjectBeanSelfProcessor"/> ...
SelfInvokerAOPTest.java
... @Test public void testSelfInvokable() { SelfInvokable selfInvoker = (SelfInvokable) ctxt.getBean("selfInvoker"); //System.out.println("JDK proxy : " + AopUtils.isJdkDynamicProxy(selfInvoker)); //selfInvoker.invoke(); //selfInvoker.method(); selfInvoker.methodFix(); } ...
运行结果
before setSelf before methodFix in SelfInvoker.methodFix... before invoke in SelfInvoker.invoke... before setSelf
3.参考资料
http://blog.163.com/yf_198407/blog/static/513854112012621105114276/
相关推荐
SpringAOP之探秘(动态代理、责任链模式、注解使用)- 详情:https://blog.csdn.net/Dream_Weave/article/details/85008674
主要介绍了spring aop之链式调用的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
1、按图所示的类图结构,设计接口及其实现类,并完成另外两附加要求:(1)日志功能:在程序执行期间追踪正在发生的活动(打印出调用的方法,以及参数的参数值);(2)验证功能:希望计算器只能处理正数的运算,当...
Spring,Bean调用,事务,AOP,配置详细说明 提升开发效率
spring的简化aop,前置通知,后置通知的简写
顾名思义,Before Advice会在目标对象的方法执行之前被调用,您可以通过实现org.springframework.aop.MethodBeforeAdvice接口来实现Before Advice的逻辑,接口定义如下: java 代码 1. package org.springframework....
基于spring4实现的AOP源代码。此源代码解压即用。
spring version: 5.0.0; jdk: 1.8 IOC大致调用顺序(IOC调用的AOP标签解析)
Spring AOP创建BeforeAdvice和AfterAdvice实例 在对象被调用前后执行方法
顾名思义,Before Advice会在目标对象的方法执行之前被调用,您可以通过实现org.springframework.aop.MethodBeforeAdvice接口来实现Before Advice的逻辑,接口定义如下: java 代码 1. package org.spring...
Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源代码解析(九):Spring Acegi框架鉴权的实现 Spring源代码解析(十):Spring Acegi框架授权...
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <context:component-scan base-package="com.spring.*"/> <aop:config> <aop:aspect id="aspect" ref="logIntercepter"> <aop:pointcut ...
AOP技术则是将日志记录和安全检测代码封装为方法,在处理业务逻辑之前分别调用已经封装好的方法即可,有效解决重复性代码的问题,并为程序开发、调试带来极大方便
Spring源代码解析(七):Spring_AOP中对拦截器调用的实现.doc
一 AOP的基本概念 (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知 (2)JointPoint(连接点):程序执行过程中明确的点,...Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
Spring AOP 学习记录 AOP(面向切面编程)方面的知识又是看了忘忘了看,今天有空记录下AOP的知识点。主要分为以下几方面: 1、AOP相关术语 2、基础知识及示例 3、增强分类 1、AOP相关术语 连接点...
Spring AOP源码04:MethodInvocation 拦截器调用 Spring AOP源码05:DefaultAdvisorAutoProxyCreator Spring期末考压轴题:当Spring AOP遇上循环依赖 git注释源码地址:...
Spring 作为 Java 中最流行的框架,主要归功于其提供的 IOC 和 AOP 功能。本文将讨论 Spring AOP 的实现。第一节将介绍 AOP 的相关概念,若熟悉可跳过,第二节中结合源码介绍 Spring 是如何实现 AOP 的各概念。 1. ...
用spring写的小示例程序,拦截某一层的所有方法。可以在调用之前、之后、抛出异常拦截调用,日志打印。
切点用于来限定Spring-AOP启动的范围,通常我们采用表达式的方式来设置,所以关键词 是范围 通知(Advice) 通知是织入到目标类连接点上的一段程序代码。在Spring中,像 BeforeAdvice等还带有方位信息 通知是直译...