/* * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.aop.aspectj.autoproxy; import junit.framework.TestCase; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests; import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator; import org.springframework.aop.aspectj.annotation.AspectMetadata; import org.springframework.aop.config.AopConfigUtils; import org.springframework.aop.framework.ProxyConfig; import org.springframework.aop.support.AopUtils; import org.springframework.beans.INestedTestBean; import org.springframework.beans.ITestBean; import org.springframework.beans.NestedTestBean; import org.springframework.beans.PropertyValue; import org.springframework.beans.TestBean; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.util.StopWatch; /** * Tests for AspectJ auto-proxying. Includes mixing with Spring AOP Advisors * to demonstrate that existing autoproxying contract is honoured. * * @author Rod Johnson * @author Juergen Hoeller */ public class AspectJAutoProxyCreatorTests extends TestCase { private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); public void testAspectsAreApplied() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspects.xml"); ITestBean tb = (ITestBean) bf.getBean("adrian"); assertEquals(68, tb.getAge()); MethodInvokingFactoryBean factoryBean = (MethodInvokingFactoryBean) bf.getBean("&factoryBean"); assertTrue(AopUtils.isAopProxy(factoryBean.getTargetObject())); assertEquals(68, ((ITestBean) factoryBean.getTargetObject()).getAge()); } public void testMultipleAspectsWithParameterApplied() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspects.xml"); ITestBean tb = (ITestBean) bf.getBean("adrian"); tb.setAge(10); assertEquals(20, tb.getAge()); } public void testAspectsAreAppliedInDefinedOrder() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspectsWithOrdering.xml"); ITestBean tb = (ITestBean) bf.getBean("adrian"); assertEquals(71, tb.getAge()); } public void testAspectsAndAdvisorAreApplied() { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); ITestBean shouldBeWeaved = (ITestBean) ac.getBean("adrian"); testAspectsAndAdvisorAreApplied(ac, shouldBeWeaved); } public void testAspectsAndAdvisorAppliedToPrototypeIsFastEnough() { if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { // Skip this test: Trace logging blows the time limit. return; } ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); StopWatch sw = new StopWatch(); sw.start("prototype"); for (int i = 0; i < 10000; i++) { ITestBean shouldBeWeaved = (ITestBean) ac.getBean("adrian2"); if (i < 10) { testAspectsAndAdvisorAreApplied(ac, shouldBeWeaved); } } sw.stop(); System.out.println(sw.getTotalTimeMillis()); assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); } public void testAspectsAndAdvisorNotAppliedToPrototypeIsFastEnough() { if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { // Skip this test: Trace logging blows the time limit. return; } ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); StopWatch sw = new StopWatch(); sw.start("prototype"); for (int i = 0; i < 100000; i++) { INestedTestBean shouldNotBeWeaved = (INestedTestBean) ac.getBean("i21"); if (i < 10) { assertFalse(AopUtils.isAopProxy(shouldNotBeWeaved)); } } sw.stop(); System.out.println(sw.getTotalTimeMillis()); assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000); } public void testAspectsAndAdvisorNotAppliedToManySingletonsIsFastEnough() { if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { // Skip this test: Trace logging blows the time limit. return; } GenericApplicationContext ac = new GenericApplicationContext(); new XmlBeanDefinitionReader(ac).loadBeanDefinitions( "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); for (int i = 0; i < 10000; i++) { ac.registerBeanDefinition("singleton" + i, new RootBeanDefinition(NestedTestBean.class)); } StopWatch sw = new StopWatch(); sw.start("singleton"); ac.refresh(); sw.stop(); System.out.println(sw.getTotalTimeMillis()); assertTrue("Singleton creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000); } public void testAspectsAndAdvisorAreAppliedEvenIfComingFromParentFactory() { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspectsPlusAdvisor.xml"); GenericApplicationContext childAc = new GenericApplicationContext(ac); // Create a child factory with a bean that should be weaved RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); bd.getPropertyValues().addPropertyValue(new PropertyValue("name", "Adrian")). addPropertyValue(new PropertyValue("age", new Integer(34))); childAc.registerBeanDefinition("adrian2", bd); // Register the advisor auto proxy creator with subclass childAc.registerBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class.getName(), new RootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class)); childAc.refresh(); ITestBean beanFromChildContextThatShouldBeWeaved = (ITestBean) childAc.getBean("adrian2"); //testAspectsAndAdvisorAreApplied(childAc, (ITestBean) ac.getBean("adrian")); testAspectsAndAdvisorAreApplied(childAc, beanFromChildContextThatShouldBeWeaved); } protected void testAspectsAndAdvisorAreApplied(ApplicationContext ac, ITestBean shouldBeWeaved) { TestBeanAdvisor tba = (TestBeanAdvisor) ac.getBean("advisor"); MultiplyReturnValue mrv = (MultiplyReturnValue) ac.getBean("aspect"); assertEquals(3, mrv.getMultiple()); tba.count = 0; mrv.invocations = 0; assertTrue("Autoproxying must apply from @AspectJ aspect", AopUtils.isAopProxy(shouldBeWeaved)); assertEquals("Adrian", shouldBeWeaved.getName()); assertEquals(0, mrv.invocations); assertEquals(34 * mrv.getMultiple(), shouldBeWeaved.getAge()); assertEquals("Spring advisor must be invoked", 2, tba.count); assertEquals("Must be able to hold state in aspect", 1, mrv.invocations); } public void testPerThisAspect() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/perthis.xml"); ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); assertTrue(AopUtils.isAopProxy(adrian1)); assertEquals(0, adrian1.getAge()); assertEquals(1, adrian1.getAge()); ITestBean adrian2 = (ITestBean) bf.getBean("adrian"); assertNotSame(adrian1, adrian2); assertTrue(AopUtils.isAopProxy(adrian1)); assertEquals(0, adrian2.getAge()); assertEquals(1, adrian2.getAge()); assertEquals(2, adrian2.getAge()); assertEquals(3, adrian2.getAge()); assertEquals(2, adrian1.getAge()); } public void testPerTargetAspect() throws SecurityException, NoSuchMethodException { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/pertarget.xml"); ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); assertTrue(AopUtils.isAopProxy(adrian1)); // Does not trigger advice or count int explicitlySetAge = 25; adrian1.setAge(explicitlySetAge); assertEquals("Setter does not initiate advice", explicitlySetAge, adrian1.getAge()); // Fire aspect AspectMetadata am = new AspectMetadata(AbstractAspectJAdvisorFactoryTests.PerTargetAspect.class, "someBean"); assertTrue(am.getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null)); adrian1.getSpouse(); assertEquals("Advice has now been instantiated", 0, adrian1.getAge()); adrian1.setAge(11); assertEquals("Any int setter increments", 2, adrian1.getAge()); adrian1.setName("Adrian"); //assertEquals("Any other setter does not increment", 2, adrian1.getAge()); ITestBean adrian2 = (ITestBean) bf.getBean("adrian"); assertNotSame(adrian1, adrian2); assertTrue(AopUtils.isAopProxy(adrian1)); assertEquals(34, adrian2.getAge()); adrian2.getSpouse(); assertEquals("Aspect now fired", 0, adrian2.getAge()); assertEquals(1, adrian2.getAge()); assertEquals(2, adrian2.getAge()); assertEquals(3, adrian1.getAge()); } public void testTwoAdviceAspectSingleton() { doTestTwoAdviceAspectWith("twoAdviceAspect.xml"); } public void testTwoAdviceAspectPrototype() { doTestTwoAdviceAspectWith("twoAdviceAspectPrototype.xml"); } private void doTestTwoAdviceAspectWith(String location) { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/" + location); boolean aspectSingleton = bf.isSingleton("aspect"); ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); testPrototype(adrian1, 0); ITestBean adrian2 = (ITestBean) bf.getBean("adrian"); assertNotSame(adrian1, adrian2); testPrototype(adrian2, aspectSingleton ? 2 : 0); } public void testAdviceUsingJoinPoint() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/usesJoinPointAspect.xml"); ITestBean adrian1 = (ITestBean) bf.getBean("adrian"); adrian1.getAge(); AdviceUsingThisJoinPoint aspectInstance = (AdviceUsingThisJoinPoint) bf.getBean("aspect"); //(AdviceUsingThisJoinPoint) Aspects.aspectOf(AdviceUsingThisJoinPoint.class); //assertEquals("method-execution(int TestBean.getAge())",aspectInstance.getLastMethodEntered()); assertTrue(aspectInstance.getLastMethodEntered().indexOf("TestBean.getAge())") != 0); } public void testIncludeMechanism() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/usesInclude.xml"); ITestBean adrian = (ITestBean) bf.getBean("adrian"); assertTrue(AopUtils.isAopProxy(adrian)); assertEquals(68, adrian.getAge()); } private void testPrototype(ITestBean adrian1, int start) { assertTrue(AopUtils.isAopProxy(adrian1)); //TwoAdviceAspect twoAdviceAspect = (TwoAdviceAspect) bf.getBean(TwoAdviceAspect.class.getName()); adrian1.setName(""); assertEquals(start++, adrian1.getAge()); int newAge = 32; adrian1.setAge(newAge); assertEquals(start++, adrian1.getAge()); adrian1.setAge(0); assertEquals(start++, adrian1.getAge()); } public void testForceProxyTargetClass() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspectsWithCGLIB.xml"); ProxyConfig pc = (ProxyConfig) bf.getBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); assertTrue("should be proxying classes", pc.isProxyTargetClass()); } public void testWithAbstractFactoryBeanAreApplied() { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/aspectsWithAbstractBean.xml"); ITestBean adrian = (ITestBean) bf.getBean("adrian"); assertTrue(AopUtils.isAopProxy(adrian)); assertEquals(68, adrian.getAge()); } public void testRetryAspect() throws Exception { ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext( "/org/springframework/aop/aspectj/autoproxy/retryAspect.xml"); UnreliableBean bean = (UnreliableBean) bf.getBean("unreliableBean"); RetryAspect aspect = (RetryAspect) bf.getBean("retryAspect"); int attempts = bean.unreliable(); assertEquals(2, attempts); assertEquals(2, aspect.getBeginCalls()); assertEquals(1, aspect.getRollbackCalls()); assertEquals(1, aspect.getCommitCalls()); } }