📄 abstractaopproxytests.java
字号:
/*
* Copyright 2002-2004 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.framework;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.ServletException;
import javax.transaction.TransactionRequiredException;
import junit.framework.TestCase;
import org.aopalliance.aop.Advice;
import org.aopalliance.aop.AspectException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.DynamicIntroductionAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.adapter.ThrowsAdviceInterceptorTests;
import org.springframework.aop.framework.adapter.UnknownAdviceTypeException;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.interceptor.NopInterceptor;
import org.springframework.aop.interceptor.SerializableNopInterceptor;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.aop.support.DynamicMethodMatcherPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.aop.support.Pointcuts;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.aop.target.HotSwappableTargetSource;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.beans.IOther;
import org.springframework.beans.ITestBean;
import org.springframework.beans.Person;
import org.springframework.beans.SerializablePerson;
import org.springframework.beans.TestBean;
import org.springframework.util.SerializationTestUtils;
import org.springframework.util.StopWatch;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @since 13-Mar-2003
*/
public abstract class AbstractAopProxyTests extends TestCase {
protected MockTargetSource mockTargetSource = new MockTargetSource();
/**
* Make a clean target source available if code wants to use it.
* The target must be set. Verification will be automatic in tearDown
* to ensure that it was used appropriately by code.
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() {
mockTargetSource.reset();
}
protected void tearDown() {
mockTargetSource.verify();
}
/**
* Set in CGLIB or JDK mode.
*/
protected abstract Object createProxy(AdvisedSupport as);
protected abstract AopProxy createAopProxy(AdvisedSupport as);
/**
* Is a target always required?
*/
protected boolean requiresTarget() {
return false;
}
public void testNoInterceptorsAndNoTarget() {
AdvisedSupport pc =
new AdvisedSupport(new Class[] { ITestBean.class });
// Add no interceptors
try {
AopProxy aop = createAopProxy(pc);
aop.getProxy();
fail("Shouldn't allow no interceptors");
} catch (AopConfigException ex) {
// Ok
}
}
private static class CheckMethodInvocationIsSameInAndOutInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
Method m = mi.getMethod();
Object retval = mi.proceed();
assertEquals("Method invocation has same method on way back", m, mi.getMethod());
return retval;
}
}
/**
* ExposeInvocation must be set to true
*/
private static class CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
String task = "get invocation on way IN";
try {
MethodInvocation current = ExposeInvocationInterceptor.currentInvocation();
assertEquals(mi, current);
Object retval = mi.proceed();
task = "get invocation on way OUT";
assertEquals(current, ExposeInvocationInterceptor.currentInvocation());
return retval;
}
catch (AspectException ex) {
System.err.println(task + " for " + mi.getMethod());
ex.printStackTrace();
//fail("Can't find invocation: " + ex);
throw ex;
}
}
}
/**
* Same thing for a proxy.
* Only works when exposeProxy is set to true.
* Checks that the proxy is the same on the way in and out.
*/
public static class ProxyMatcherInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
Object proxy = AopContext.currentProxy();
Object ret = mi.proceed();
// TODO why does this cause stack overflow?
//assertEquals(proxy, AopContext.currentProxy());
assertTrue(proxy == AopContext.currentProxy());
return ret;
}
}
/**
* Simple test that if we set values we can get them out again
*
*/
public void testValuesStick() {
int age1 = 33;
int age2 = 37;
String name = "tony";
TestBean target1 = new TestBean();
target1.setAge(age1);
ProxyFactory pf1 = new ProxyFactory(target1);
pf1.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()));
pf1.addAdvisor(new DefaultPointcutAdvisor(new TimestampIntroductionInterceptor()));
ITestBean tb = (ITestBean) target1;
assertEquals(age1, tb.getAge());
tb.setAge(age2);
assertEquals(age2, tb.getAge());
assertNull(tb.getName());
tb.setName(name);
assertEquals(name, tb.getName());
}
/**
* This is primarily a test for the efficiency of our
* usage of CGLIB. If we create too many classes with
* CGLIB this will be slow or will run out of memory
* TODO reenable this
*
*/
public void testManyProxies() {
int howmany = 10000;
StopWatch sw = new StopWatch();
sw.start(getClass() + getName() + ": create " + howmany + " proxies");
testManyProxies(howmany);
sw.stop();
System.out.println(sw);
// Set a performance benchmark
// It's pretty generous so as not to cause failures
// on slow machines
assertTrue("Proxy creation was too slow",
sw.getTotalTimeSeconds() < 20);
}
private void testManyProxies(int howmany) {
int age1 = 33;
TestBean target1 = new TestBean();
target1.setAge(age1);
ProxyFactory pf1 = new ProxyFactory(target1);
pf1.addAdvice(new NopInterceptor());
pf1.addAdvice(new NopInterceptor());
ITestBean proxies[] = new ITestBean[howmany];
for (int i = 0; i < howmany; i++) {
proxies[i] = (ITestBean) createAopProxy(pf1).getProxy();
assertEquals(age1, proxies[i].getAge());
}
}
public void testSerializationAdviceAndTargetNotSerializable() throws Exception {
TestBean tb = new TestBean();
assertFalse(SerializationTestUtils.isSerializable(tb));
ProxyFactory pf = new ProxyFactory(tb);
pf.addAdvice(new NopInterceptor());
ITestBean proxy = (ITestBean) createAopProxy(pf).getProxy();
assertFalse(SerializationTestUtils.isSerializable(proxy));
}
public void testSerializationAdviceNotSerializable() throws Exception {
SerializablePerson sp = new SerializablePerson();
assertTrue(SerializationTestUtils.isSerializable(sp));
ProxyFactory pf = new ProxyFactory(sp);
// This isn't serializable
Advice i = new NopInterceptor();
pf.addAdvice(i);
assertFalse(SerializationTestUtils.isSerializable(i));
Object proxy = createAopProxy(pf).getProxy();
assertFalse(SerializationTestUtils.isSerializable(proxy));
}
public void testSerializationSerializableTargetAndAdvice() throws Throwable {
SerializablePerson personTarget = new SerializablePerson();
personTarget.setName("jim");
personTarget.setAge(26);
assertTrue(SerializationTestUtils.isSerializable(personTarget));
ProxyFactory pf = new ProxyFactory(personTarget);
CountingThrowsAdvice cta = new CountingThrowsAdvice();
pf.addAdvice(new SerializableNopInterceptor());
// Try various advice types
pf.addAdvice(new CountingBeforeAdvice());
pf.addAdvice(new CountingAfterReturningAdvice());
pf.addAdvice(cta);
Person p = (Person) createAopProxy(pf).getProxy();
p.echo(null);
assertEquals(0, cta.getCalls());
try {
p.echo(new ServletException());
}
catch (ServletException ex) {
}
assertEquals(1, cta.getCalls());
// Will throw exception if it fails
Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p);
assertNotSame(p, p2);
assertEquals(p.getName(), p2.getName());
assertEquals(p.getAge(), p2.getAge());
assertTrue("Deserialized object is an AOP proxy", AopUtils.isAopProxy(p2));
Advised a1 = (Advised) p;
Advised a2 = (Advised) p2;
// Check we can manipulate state of p2
assertEquals(a1.getAdvisors().length, a2.getAdvisors().length);
// This should work as SerializablePerson is equal
assertEquals("Proxies should be equal, even after one was serialized", p, p2);
assertEquals("Proxies should be equal, even after one was serialized", p2, p);
// Check we can add a new advisor to the target
NopInterceptor ni = new NopInterceptor();
p2.getAge();
assertEquals(0, ni.getCount());
a2.addAdvice(ni);
p2.getAge();
assertEquals(1, ni.getCount());
cta = (CountingThrowsAdvice) a2.getAdvisors()[3].getAdvice();
p2.echo(null);
assertEquals(1, cta.getCalls());
try {
p2.echo(new ServletException());
}
catch (ServletException ex) {
}
assertEquals(2, cta.getCalls());
}
/**
* Check that the two MethodInvocations necessary are independent and
* don't conflict.
* Check also proxy exposure.
*/
public void testOneAdvisedObjectCallsAnother() {
int age1 = 33;
int age2 = 37;
TestBean target1 = new TestBean();
ProxyFactory pf1 = new ProxyFactory(target1);
// Permit proxy and invocation checkers to get context from AopContext
pf1.setExposeProxy(true);
NopInterceptor di1 = new NopInterceptor();
pf1.addAdvice(0, di1);
pf1.addAdvice(1, new ProxyMatcherInterceptor());
pf1.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor());
pf1.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor());
// Must be first
pf1.addAdvice(0, ExposeInvocationInterceptor.INSTANCE);
ITestBean advised1 = (ITestBean) pf1.getProxy();
advised1.setAge(age1); // = 1 invocation
TestBean target2 = new TestBean();
ProxyFactory pf2 = new ProxyFactory(target2);
pf2.setExposeProxy(true);
NopInterceptor di2 = new NopInterceptor();
pf2.addAdvice(0, di2);
pf2.addAdvice(1, new ProxyMatcherInterceptor());
pf2.addAdvice(2, new CheckMethodInvocationIsSameInAndOutInterceptor());
pf2.addAdvice(1, new CheckMethodInvocationViaThreadLocalIsSameInAndOutInterceptor());
pf2.addAdvice(0, ExposeInvocationInterceptor.INSTANCE);
//System.err.println(pf2.toProxyConfigString());
ITestBean advised2 = (ITestBean) createProxy(pf2);
advised2.setAge(age2);
advised1.setSpouse(advised2); // = 2 invocations
assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations
assertEquals("Advised two has correct age", age2, advised2.getAge());
// Means extra call on advised 2
assertEquals("Advised one spouse has correct age", age2, advised1.getSpouse().getAge()); // = 4 invocations on 1 and another one on 2
assertEquals("one was invoked correct number of times", 4, di1.getCount());
// Got hit by call to advised1.getSpouse().getAge()
assertEquals("one was invoked correct number of times", 3, di2.getCount());
}
public void testReentrance() {
int age1 = 33;
TestBean target1 = new TestBean();
ProxyFactory pf1 = new ProxyFactory(target1);
NopInterceptor di1 = new NopInterceptor();
pf1.addAdvice(0, di1);
ITestBean advised1 = (ITestBean) createProxy(pf1);
advised1.setAge(age1); // = 1 invocation
advised1.setSpouse(advised1); // = 2 invocations
assertEquals("one was invoked correct number of times", 2, di1.getCount());
assertEquals("Advised one has correct age", age1, advised1.getAge()); // = 3 invocations
assertEquals("one was invoked correct number of times", 3, di1.getCount());
// = 5 invocations, as reentrant call to spouse is advised also
assertEquals("Advised spouse has correct age", age1, advised1.getSpouse().getAge());
assertEquals("one was invoked correct number of times", 5, di1.getCount());
}
public interface INeedsToSeeProxy {
int getCount();
void incrementViaThis();
void incrementViaProxy();
void increment();
}
public static class NeedsToSeeProxy implements INeedsToSeeProxy {
private int count;
public int getCount() {
return count;
}
public void incrementViaThis() {
this.increment();
}
public void incrementViaProxy() {
INeedsToSeeProxy thisViaProxy = (INeedsToSeeProxy) AopContext.currentProxy();
thisViaProxy.increment();
Advised advised = (Advised) thisViaProxy;
checkAdvised(advised);
}
protected void checkAdvised(Advised advised) {
}
public void increment() {
++count;
}
}
public static class TargetChecker extends NeedsToSeeProxy {
protected void checkAdvised(Advised advised) {
// TODO replace this check: no longer possible
//assertEquals(advised.getTarget(), this);
}
}
public void testTargetCanGetProxy() {
NopInterceptor di = new NopInterceptor();
INeedsToSeeProxy target = new TargetChecker();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.setExposeProxy(true);
assertTrue(proxyFactory.getExposeProxy());
proxyFactory.addAdvice(0, di);
INeedsToSeeProxy proxied = (INeedsToSeeProxy) createProxy(proxyFactory);
assertEquals(0, di.getCount());
assertEquals(0, target.getCount());
proxied.incrementViaThis();
assertEquals("Increment happened", 1, target.getCount());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -