Spring Aop
代理机制
静态代理机制
代理对象和被代理对象必须实现同一个接口 可以按业务分开 不同服务呼叫不同业务对象
动态代理机制
设计一个类实现java.lang.reflect.InvocationHandler 于原有业务不相干 不用知道会调用谁
AOP术语
Cross-cutting concern 横切到业务流程中
Aspect 把Cross-cutting concern组织起来 设计成可重用的对象 AOP强调独立 重用时不用做任何的修改
AdviceAspect的具体实现 在java中就是具体的类
Joinpoint 插入点和时机
Pointcut组织Advice和Joinpoint
Target被Advice应用的对象和目标
Introduction 对于一个现存的类 Introduction可以增加行为 而不用修改改类的程序
Proxy
Weave Advice被应用于对象之上的过程为织入
Advice
BeforeAdvice
例子
IHello.java
public interface IHello
{
public void hello(Stringname);
}
HelloSpeaker.java
public class HelloSpeaker implements IHello
{
public void hello(Stringname)
{
System.out.println( " hello! " + name);
}
}
LogBeforeAdvice.java
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.aop.MethodBeforeAdvice;
public class LogBeforeAdvice implements MethodBeforeAdvice
{
private Loggerlogger = Logger.getLogger( this .getClass().getName());
public void before(Methodmethod,Object[]args,Objecttarget) throws Throwable
{
logger.log(Level.INFO, " methodstarts.... " ,method);
}
}
beans-config.xml
<! DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="logBeforeAdvice" class ="com.ergal.spring.LogBeforeAdvice" />
< bean id ="helloSpeaker" class ="com.ergal.spring.HelloSpeaker" />
< bean id ="helloProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="proxyInterfaces" >
< value > com.ergal.spring.IHello </ value >
</ property >
< property name ="target" >
< ref bean ="helloSpeaker" />
</ property >
< property name ="interceptorNames" >
< list >
< value > logBeforeAdvice </ value >
</ list >
</ property >
</ bean >
</ beans >
SpringDemo.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo
{
public static void main(String[]args)
{
ApplicationContextcontext = new FileSystemXmlApplicationContext( " beans-config.xml " );
IHellohelloproxy = (IHello)context.getBean( " helloProxy " );
helloproxy.hello( " Rainytooo " );
}
}
测试结果
2006-9-300:31:17org.springframework.aop.framework.DefaultAopProxyFactory<clinit>
信息:CGLIB2notavailable:proxyTargetClassfeaturedisabled
2006-9-300:31:17com.ergal.spring.LogBeforeAdvicebefore
信息:methodstarts....
hello!Rainytooo
AfterAdvice 稍加修改即可
AroundAdvice
LogInterceptor.java
import java.util.logging.Level;
import java.util.logging.Logger;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LogInterceptor implements MethodInterceptor
{
private Loggerlogger = Logger.getLogger( this .getClass().getName());
public Objectinvoke(MethodInvocationmethodInvocation) throws Throwable
{
logger.log(Level.INFO, " methodstart.... " + methodInvocation.getMethod());
Objectresult = null ;
try
{
result = methodInvocation.proceed();
}
finally
{
logger.log(Level.INFO, " methodend... " + methodInvocation.getMethod() + " " );
}
return result;
}
}
beans-config.xml
<! DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="logBeforeAdvice" class ="com.ergal.spring.LogBeforeAdvice" />
< bean id ="logAfterAdvice" class ="com.ergal.spring.LogAfterAdvice" />
< bean id ="helloSpeaker" class ="com.ergal.spring.HelloSpeaker" />
< bean id ="logInterceptor" class ="com.ergal.spring.LogInterceptor" />
< bean id ="helloProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="proxyInterfaces" >
< value > com.ergal.spring.IHello </ value >
</ property >
< property name ="target" >
< ref bean ="helloSpeaker" />
</ property >
< property name ="interceptorNames" >
< list >
< value > logInterceptor </ value >
</ list >
</ property >
</ bean >
</ beans >
Throw Advice
在发生异常的时候同志某些服务对象做某些事
例子
IHello.java
public interface IHello
{
public void hello(Stringname) throws Throwable;
}
HelloSpeaker.java
public class HelloSpeaker implements IHello
{
public void hello(Stringname) throws Throwable
{
System.out.println( " hello! " + name);
throw new Exception( " 发生异常 " );
}
}
SomeThrowAdvice.java
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.aop.ThrowsAdvice;
public class SomeThrowAdvice implements ThrowsAdvice
{
private Loggerlogger = Logger.getLogger( this .getClass().getName());
public void afterThrowing(Methodmethod,Object[]args,Objecttarget,Throwablesubclass)
{
logger.log(Level.INFO, " Loggingthata " + subclass + " Exceptionwasthrownin " + method);
}
}
beans-config.xml
<! DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="someThrowAdvice" class ="com.ergal.spring.SomeThrowAdvice" />
< bean id ="helloSpeaker" class ="com.ergal.spring.HelloSpeaker" />
< bean id ="helloProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="proxyInterfaces" >
< value > com.ergal.spring.IHello </ value >
</ property >
< property name ="target" >
< ref bean ="helloSpeaker" />
</ property >
< property name ="interceptorNames" >
< list >
< value > someThrowAdvice </ value >
</ list >
</ property >
</ bean >
</ beans >
SpringDemo.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo
{
public static void main(String[]args)
{
ApplicationContextcontext = new FileSystemXmlApplicationContext( " beans-config.xml " );
IHellohelloproxy = (IHello)context.getBean( " helloProxy " );
try
{
helloproxy.hello( " Rainytooo " );
}
catch (Throwablethrowable)
{
System.err.println(throwable);
}
}
}
结果
2006-9-304:07:47org.springframework.core.CollectionFactory<clinit>
信息:JDK1.4+collectionsavailable
2006-9-304:07:48org.springframework.beans.factory.xml.XmlBeanDefinitionReaderloadBeanDefinitions
信息:LoadingXMLbeandefinitionsfromfile[D:workspacespringdemoeans-config.xml]
2006-9-304:07:48org.springframework.context.support.AbstractRefreshableApplicationContextrefreshBeanFactory
信息:Beanfactoryforapplicationcontext[org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=8795033]:org.springframework.beans.factory.support.DefaultListableBeanFactorydefiningbeans[someThrowAdvice,helloSpeaker,helloProxy];rootofBeanFactoryhierarchy
2006-9-304:07:48org.springframework.context.support.AbstractApplicationContextrefresh
信息:3beansdefinedinapplicationcontext[org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=8795033]
2006-9-304:07:48org.springframework.context.support.AbstractApplicationContextinitMessageSource
信息:UnabletolocateMessageSourcewithname'messageSource':usingdefault[org.springframework.context.support.DelegatingMessageSource@1034bb5]
2006-9-304:07:48org.springframework.context.support.AbstractApplicationContextinitApplicationEventMulticaster
信息:UnabletolocateApplicationEventMulticasterwithname'applicationEventMulticaster':usingdefault[org.springframework.context.event.SimpleApplicationEventMulticaster@1cfb549]
2006-9-304:07:48org.springframework.beans.factory.support.DefaultListableBeanFactorypreInstantiateSingletons
信息:Pre-instantiatingsingletonsinfactory[org.springframework.beans.factory.support.DefaultListableBeanFactorydefiningbeans[someThrowAdvice,helloSpeaker,helloProxy];rootofBeanFactoryhierarchy]
2006-9-304:07:48org.springframework.aop.framework.DefaultAopProxyFactory<clinit>
信息:CGLIB2notavailable:proxyTargetClassfeaturedisabled
2006-9-304:07:48com.ergal.spring.SomeThrowAdviceafterThrowing
信息:Loggingthatajava.lang.Exception:发生异常Exceptionwasthrowninpublicabstractvoidcom.ergal.spring.IHello.hello(java.lang.String)throwsjava.lang.Throwable
java.lang.Exception:发生异常
Pointcut
定义了Advice的应用时机 在Spring中 使用PointcutAdvisor 将Pointcut和Advice合成为一个对象 Spring内建的Pointcut都有对应的PointcutAdvisor
NameMatchMethodPointcutAdvisor
这是静态的
例子
IHello.java
public interface IHello
{
public void helloNewbie(Stringname);
public void helloMaster(Stringname);
}
HelloSpeaker.java
public class HelloSpeaker implements IHello
{
public void helloNewbie(Stringname)
{
// TODOAuto-generatedmethodstub
System.out.println( " Hello! " + name + " Newbie " );
}
public void helloMaster(Stringname)
{
// TODOAuto-generatedmethodstub
System.out.println( " Hello! " + name + " Master " );
}
}
LogbeforeAdvice.java
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.aop.MethodBeforeAdvice;
public class LogBeforeAdvice implements MethodBeforeAdvice
{
private Loggerlogger = Logger.getLogger( this .getClass().getName());
public void before(Methodmethod,Object[]args,Objecttarget) throws Throwable
{
logger.log(Level.INFO, " methodstarts.... " ,method);
}
}
beans-config.xml
<! DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="logBeforeAdvice" class ="com.ergal.spring.LogBeforeAdvice" />
< bean id ="helloSpeaker" class ="com.ergal.spring.HelloSpeaker" />
< bean id ="helloAdvisor" class ="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" >
< property name ="mappedName" >
< value > hello* </ value >
</ property >
< property name ="advice" >
< ref bean ="logBeforeAdvice" />
</ property >
</ bean >
< bean id ="helloProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="proxyInterfaces" >
< value > com.ergal.spring.IHello </ value >
</ property >
< property name ="target" >
< ref bean ="helloSpeaker" />
</ property >
< property name ="interceptorNames" >
< list >
< value > helloAdvisor </ value >
</ list >
</ property >
</ bean >
</ beans >
SPringDemo.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo
{
public static void main(String[]args)
{
ApplicationContextcontext = new FileSystemXmlApplicationContext( " beans-config.xml " );
IHellohelloProxy = (IHello)context.getBean( " helloProxy " );
helloProxy.helloNewbie( " wang " );
helloProxy.helloMaster( " zhang " );
}
}
测试结果
信息:methodstarts....
2006-9-306:04:49com.ergal.spring.LogBeforeAdvicebefore
信息:methodstarts....
Hello!wangNewbie
Hello!zhangMaster
在Eclipse下运行怎么结果不一样
ComtrolFlowPointcut
org.springframework.aop.support.ControlFlowPointcut 是Spring说提供的类 作为判断在方法的执行堆栈中 某个指定类的方法中 是否曾经要求您的目标对象执行某个动作 由于这是在执行过程中才决定是否介入Advice 所以是动态的
例子
Some.java
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class Some implements ApplicationContextAware
{
private IHellohelloProxy;
public void setApplicationContext(ApplicationContextcontext)
throws BeansException
{
// TODOAuto-generatedmethodstub
helloProxy = (IHello)context.getBean( " helloProxy " );
}
public void helloEveryBody()
{
helloProxy.helloNewbie( " Wang " );
helloProxy.helloMaster( " Zhang " );
}
}
SpringDemo.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo
{
public static void main(String[]args)
{
ApplicationContextcontext = new FileSystemXmlApplicationContext( " beans-config.xml " );
Somesome = (Some)context.getBean( " some " );
// some.helloEveryBody();
System.out.println( " Nothing " );
}
}
beans-config.xml
<! DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="some" class ="com.ergal.spring.Some" />
< bean id ="logBeforeAdvice" class ="com.ergal.spring.LogBeforeAdvice" />
< bean id ="helloSpeaker" class ="com.ergal.spring.HelloSpeaker" />
< bean id ="helloFlowControlPointcut" class ="org.springframework.aop.support.ControlFlowPointcut" >
< constructor-arg >
< value > com.ergal.spring.Some </ value >
</ constructor-arg >
</ bean >
< bean id ="helloAdvisor" class ="org.springframework.aop.support.DefaultPointcutAdvisor" >
< property name ="advice" >
< ref bean ="logBeforeAdvice" />
</ property >
< property name ="pointcut" >
< ref bean ="helloFlowControlPointcut" />
</ property >
</ bean >
< bean id ="helloProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="proxyInterfaces" >
< value > com.ergal.spring.IHello </ value >
</ property >
< property name ="target" >
< ref bean ="helloSpeaker" />
</ property >
< property name ="interceptorNames" >
< list >
< value > helloAdvisor </ value >
</ list >
</ property >
</ bean >
</ beans >
这样在执行方法和不执行方法的时候就有区别了 从而实现了动态的Pointcut
Introduction
追加 可以给现有的类增加方法
修改 从而分离原来的类 不影响(我是这么理解的)
比如这个类IntroductionInterceptor
例子来说明
Some.java
public interface Some
{
public void doSome();
}
Someone.java
public class Someone implements Some
{
public void doSome()
{
// TODOAuto-generatedmethodstub
System.out.println( " 原来要做的事情......... " );
}
}
Other.java
public interface Other
{
public void doOther();
}
Otherone.java
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.IntroductionInterceptor;
public class Otherone implements Other,IntroductionInterceptor
{
public void doOther()
{
// TODOAuto-generatedmethodstub
System.out.println( " 后来添加的事情进来....... " );
}
public Objectinvoke(MethodInvocationarg0) throws Throwable
{
// TODOAuto-generatedmethodstub
if (implementsInterface(arg0.getMethod().getDeclaringClass()))
{
return arg0.getMethod().invoke( this ,arg0.getArguments());
}
else
{
return arg0.proceed();
}
}
public boolean implementsInterface(Classarg0)
{
// TODOAuto-generatedmethodstub
return arg0.isAssignableFrom(Other. class );
}
}
SpringDemo.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo
{
public static void main(String[]args)
{
ApplicationContextcontext = new FileSystemXmlApplicationContext( " beans-config.xml " );
Somesome = (Some)context.getBean( " helloProxy " );
some.doSome();
((Other)some).doOther();
}
}
beans-config.xml
<! DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="someone" class ="com.ergal.spring.Someone" />
< bean id ="otherone" class ="com.ergal.spring.Otherone" />
< bean id ="otherAdvice" class ="org.springframework.aop.support.DefaultIntroductionAdvisor" >
< constructor-arg index ="0" >
< ref bean ="otherone" />
</ constructor-arg >
< constructor-arg index ="1" >
< value > com.ergal.spring.Other </ value >
</ constructor-arg >
</ bean >
< bean id ="helloProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="proxyInterfaces" >
< value > com.ergal.spring.Some </ value >
</ property >
< property name ="target" >
< ref bean ="someone" />
</ property >
< property name ="interceptorNames" >
< list >
< value > otherAdvice </ value >
</ list >
</ property >
</ bean >
</ beans >
结果
2006-9-30 10:04:30 org.springframework.core.CollectionFactory <clinit>
信息: JDK 1.4+ collections available
2006-9-30 10:04:30 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from file [D:/workspace/springdemo/beans-config.xml]
2006-9-30 10:04:30 org.springframework.context.support.AbstractRefreshableApplicationContext refreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=8795033]: org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [someone,otherone,otherAdvice,helloProxy]; root of BeanFactory hierarchy
2006-9-30 10:04:30 org.springframework.context.support.AbstractApplicationContext refresh
信息: 4 beans defined in application context [org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=8795033]
2006-9-30 10:04:30 org.springframework.context.support.AbstractApplicationContext initMessageSource
信息: Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@87816d]
2006-9-30 10:04:30 org.springframework.context.support.AbstractApplicationContext initApplicationEventMulticaster
信息: Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@1d9dc39]
2006-9-30 10:04:30 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in factory [org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [someone,otherone,otherAdvice,helloProxy]; root of BeanFactory hierarchy]
2006-9-30 10:04:30 org.springframework.aop.framework.DefaultAopProxyFactory <clinit>
信息: CGLIB2 not available: proxyTargetClass feature disabled
原来要做的事情.........
后来添加的事情进来.......
DelegatingIntroductionInterceptor
在不改变原有对象的状态下给目标对象添加 状态 来实现锁定
例子
Some.java
public interface Some
{
public void setSome(Stringsome);
public StringgetSome();
}
Someone.java
public class Someone implements Some
{
private Stringsome;
public void setSome(Stringsome)
{
// TODOAuto-generatedmethodstub
this .some = some;
}
public StringgetSome()
{
return some;
}
}
ILockable.java
public interface ILockable
{
public void lock();
public void unlock();
public boolean isLocked();
}
LockIntroduction.java
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class LockIntroduction extends DelegatingIntroductionInterceptor implements ILockable
{
private boolean locked;
public Objectinvoke(MethodInvocationinvocation) throws Throwable
{
if (isLocked() && invocation.getMethod().getName().indexOf( " set " ) == 0 )
{
throw new AopConfigException( " 物件被锁定... " );
}
return super .invoke(invocation);
}
public boolean isLocked() {
// TODOAuto-generatedmethodstub
return locked;
}
public void lock() {
// TODOAuto-generatedmethodstub
locked = true ;
}
public void unlock() {
// TODOAuto-generatedmethodstub
locked = false ;
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo
{
public static void main(String[]args)
{
ApplicationContextcontext = new FileSystemXmlApplicationContext( " beans-config.xml " );
Somesome = (Some)context.getBean( " helloProxy " );
some.setSome( " wang " );
System.out.println(some.getSome());
try
{
((ILockable)some).lock();
some.setSome( " zhang " );
System.out.println(some.getSome());
}
catch (Throwablee)
{
e.printStackTrace();
}
((ILockable)some).unlock();
some.setSome( " zhang " );
System.out.println(some.getSome());
}
}
beans-config.xml
<! DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean id ="someone" class ="com.ergal.spring.Someone" />
< bean id ="lockIntroduction" class ="com.ergal.spring.LockIntroduction" />
< bean id ="lockAdvisor" class ="org.springframework.aop.support.DefaultIntroductionAdvisor" >
< constructor-arg index ="0" >
< ref bean ="lockIntroduction" />
</ constructor-arg >
< constructor-arg index ="1" >
< value > com.ergal.spring.ILockable </ value >
</ constructor-arg >
</ bean >
< bean id ="helloProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" >
< property name ="proxyInterfaces" >
< value > com.ergal.spring.Some </ value >
</ property >
< property name ="target" >
< ref bean ="someone" />
</ property >
< property name ="interceptorNames" >
< list >
< value > lockAdvisor </ value >
</ list >
</ property >
</ bean >
</ beans >
结果
信息:JDK1.4+collectionsavailable
2006-9-3010:47:34org.springframework.beans.factory.xml.XmlBeanDefinitionReaderloadBeanDefinitions
信息:LoadingXMLbeandefinitionsfromfile[D:workspacespringdemoeans-config.xml]
2006-9-3010:47:34org.springframework.context.support.AbstractRefreshableApplicationContextrefreshBeanFactory
信息:Beanfactoryforapplicationcontext[org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=8795033]:org.springframework.beans.factory.support.DefaultListableBeanFactorydefiningbeans[someone,lockIntroduction,lockAdvisor,helloProxy];rootofBeanFactoryhierarchy
2006-9-3010:47:34org.springframework.context.support.AbstractApplicationContextrefresh
信息:4beansdefinedinapplicationcontext[org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=8795033]
2006-9-3010:47:34org.springframework.context.support.AbstractApplicationContextinitMessageSource
信息:UnabletolocateMessageSourcewithname'messageSource':usingdefault[org.springframework.context.support.DelegatingMessageSource@1d9dc39]
2006-9-3010:47:34org.springframework.context.support.AbstractApplicationContextinitApplicationEventMulticaster
信息:UnabletolocateApplicationEventMulticasterwithname'applicationEventMulticaster':usingdefault[org.springframework.context.event.SimpleApplicationEventMulticaster@111a3ac]
2006-9-3010:47:34org.springframework.beans.factory.support.DefaultListableBeanFactorypreInstantiateSingletons
信息:Pre-instantiatingsingletonsinfactory[org.springframework.beans.factory.support.DefaultListableBeanFactorydefiningbeans[someone,lockIntroduction,lockAdvisor,helloProxy];rootofBeanFactoryhierarchy]
2006-9-3010:47:34org.springframework.aop.framework.DefaultAopProxyFactory<clinit>
信息:CGLIB2notavailable:proxyTargetClassfeaturedisabled
org.springframework.aop.framework.AopConfigException:物件被锁定...
atcom.ergal.spring.LockIntroduction.invoke(LockIntroduction.java:15)
atorg.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
atorg.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
at$Proxy0.setSome(UnknownSource)
atcom.ergal.spring.SpringDemo.main(SpringDemo.java:21)
wang
zhang
自动代理
怕怕