Spring AOP如何让内部方法调用也发生代理

原创 2018年04月17日 15:47:39

方法之间的调用直接使用的是原始对象,而非代理对象,因而内部调用不会产生代理

public class Waiter {
    public void greetTo(String name) {
        System.out.println("greet to :" + name);
    }

    public void serveTo(String name) {
        System.out.println("serve to :" + name);
        greetTo(name);
    }
public class Seller {
    public void greetTo(String name) {
        System.out.println("greet to :" + name);
    }
}
    <bean id="waiter" class="com.demo.aop.Waiter"/>
    <bean id="seller" class="com.demo.aop.Seller"/>
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:patterns=".*To.*">
        <property name="advice">
            <bean class="com.demo.aop.GreetingAdvice"/>
        </property>
    </bean>
    <!--自动根据advisor生成代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          p:proxyTargetClass="true"/>

测试类:

@ContextConfiguration(locations = {"classpath:spring-context.xml"})
public class Test extends AbstractJUnit4SpringContextTests {
    @org.junit.Test
    public void test1() {
        Waiter waiter = (Waiter) applicationContext.getBean("waiter");
        Seller seller = (Seller) applicationContext.getBean("seller");
        System.out.println("---------------------------");
        waiter.greetTo("John");
        System.out.println("---------------------------");
        waiter.serveTo("Ivern");
        System.out.println("---------------------------");
        seller.greetTo("Lili");
    }
}

结果:greet方法的内部调用没有生成代理



修改:

/**
 * 自动装配代理对象接口
 */
public interface BeanSelfProxyAware {
    void setBeanSelfProxy(Object proxyObj);
}
/**
 * 自定义容器启动插件
 */
public interface SystemBootAddon extends Ordered {
    void onReady();
}
/**
 * 自定义管理器,当启动完成时,对实现了BeanSelfProxyAware接口的bean注入proxyBean
 */
public class BeanSelfProxyMonter implements ApplicationContextAware, SystemBootAddon {
    private ApplicationContext applicationContext;

    public void onReady() {
        Map<String, BeanSelfProxyAware> proxyAwares = applicationContext.getBeansOfType(BeanSelfProxyAware.class);
        for (BeanSelfProxyAware proxyAware : proxyAwares.values()) {
            proxyAware.setBeanSelfProxy(proxyAware);
        }
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
/**
 * 消息监听器,监听Spring系统消息
 */
public class SystemBootManager implements ApplicationListener<ContextRefreshedEvent> {
    private List<SystemBootAddon> systemBootAddons;
    private boolean hasRunOnce = false;

    /**
     * Spring自动注入所有的SystemBootAddon
     *
     * @param systemBootAddons
     */
    @Autowired
    public void setSystemBootAddons(List<SystemBootAddon> systemBootAddons) {
        this.systemBootAddons = systemBootAddons;
    }

    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        if (!hasRunOnce) {
            for (SystemBootAddon systemBootAddon :systemBootAddons) {
                systemBootAddon.onReady();
            }
            hasRunOnce = true;
        }
    }
}
<bean id="waiter" class="com.demo.aop.Waiter"/>
    <bean id="seller" class="com.demo.aop.Seller"/>
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:patterns=".*To.*">
        <property name="advice">
            <bean class="com.demo.aop.GreetingAdvice"/>
        </property>
    </bean>
    <!--自动根据advisor生成代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          p:proxyTargetClass="true"/>
    <!--注册启动器-->
    <bean class="com.demo.aop.BeanSelfProxyMonter"/>
    <!--注册启动加载器-->
    <bean class="com.demo.aop.SystemBootManager"/>
public class Waiter implements BeanSelfProxyAware {
    private Waiter waiterProxy;

    public void setBeanSelfProxy(Object proxyObj) {
        this.waiterProxy = (Waiter) proxyObj;
    }

    public void greetTo(String name) {
        System.out.println("greet to :" + name);
    }

    public void serveTo(String name) {
        System.out.println("serve to :" + name);
        waiterProxy.greetTo(name);
    }
}

最后的结果:







spring AOP中自身方法调用无法应用代理解决办法

spring AOP中自身方法调用无法应用代理解决办法 AopContext
  • tangtong1
  • tangtong1
  • 2017-02-06 15:40:29
  • 1055

spring aop之对象内部方法间的嵌套失效

spring aop之对象内部方法间的嵌套失效 先看一下spring 代理原理: *       spring代理嵌套方法调用不生效  *   *       Spring AOP d...
  • doctor_who2004
  • doctor_who2004
  • 2016-07-03 12:09:11
  • 4693

Spring3.1.0实现原理分析(十).AOP代理对象执行拦截过程

大家好,上篇博客讲解了代理对象的创建过程《AOP之创建代理对象的过程》,今天主要分析下代理对象执行拦截的过程。无论是jdk代理对象还是cglib代理对象,它们都持有通知列表对象,而通知对象呢其实就是A...
  • roberts939299
  • roberts939299
  • 2017-05-26 17:30:08
  • 256

解决spring aop无法拦截代理内部函数调用的问题

code如下: public class ServiceAImpl implements ServiceA{ public void function01(...){ ....
  • russ44
  • russ44
  • 2018-01-04 22:06:31
  • 142

spring之aop方法内部调用问题

现象描述:假设有一个service,其中有A B 两个方法,A B都被aop托管,且A中调用了B方法,这时请求方法A的时候只会触发A的aop逻辑而不会触发B的aop逻辑。public interfac...
  • nieyanshun_me
  • nieyanshun_me
  • 2017-07-09 21:20:48
  • 1569

关于拦截方法调用其他内部方法无法被拦截问题的解决

【创建时间】2016/9/8 这篇文章是我转载的一篇,当时正好碰到无法理解为什么spring的事务在类内部方法调用时无效,这篇文章解释了这个问题。 拦截器的实现原理很简单,就是动态代理,实现A...
  • FreemanZhao
  • FreemanZhao
  • 2017-02-07 23:31:31
  • 636

Spring AOP无法拦截对象的内部方法调用问题

参考: http://fyting.iteye.com/blog/109236
  • luojinbai
  • luojinbai
  • 2017-01-19 08:20:14
  • 1451

Spring AOP不拦截从对象内部调用的方法原因

拦截器的实现原理很简单,就是动态代理,实现AOP机制。当外部调用被拦截bean的拦截方法时,可以选择在拦截之前或者之后等条件执行拦截方法之外的逻辑,比如特殊权限验证,参数修正等操作。   但是最近在...
  • TianDiYiShaOu_
  • TianDiYiShaOu_
  • 2016-04-21 10:10:34
  • 1600

spring aop实现类似代理类和类中的方法(注解实现)

1.可以指定aop的执行次序 2.@within,可以拦截类上有@DataSource注解的类中的所有方法 3.@annotation可以拦截有注解@DataSource的方法...
  • y_wave
  • y_wave
  • 2016-09-12 09:33:03
  • 575

spring aop类内部调用不拦截原因及解决方案

spring对应java web开发的同学来说,都不陌生,其中事务@Transactional在service层更是常常使用。 1.aop类内部调用不拦截原因 细心的同学也许早就发现当servic...
  • dream_broken
  • dream_broken
  • 2017-06-08 11:51:09
  • 3471
收藏助手
不良信息举报
您举报文章:Spring AOP如何让内部方法调用也发生代理
举报原因:
原因补充:

(最多只允许输入30个字)