Preface
As one of the important features of spring, the role of AOP is of course unquestionable. It allows us to cut through the code during the execution of the code, encapsulating the actions that are performed repeatedly. Ensure the modularity and ease of management of your code. This blog post will explain how AOP works and uses it from a source point of view:
a simple AOP implementation
<!--bean.xml to
<bean id= "Testadvice" class= "CHAPTER3_AOP. Testadvice "></bean>
<bean id=" AOP "class=" Org.springframework.aop.framework.ProxyFactoryBean " >
<!--optional
--<property name= "proxyinterfaces" >
<value>chapter3_aop. operateapi</value>
</property>
<property name= "target" >
<bean class= "chapter3_ Aop. Operatetarget "></bean>
</property>
<property name=" Interceptornames ">
< list>
<value>testadvice</value>
</list>
</property>
</bean >
Operatetarget.java public
class Operatetarget implements operateapi{
@Override public
Void Update () {
System.out.println ("Update");
}
}
Testadvice.java public
class Testadvice implements methodbeforeadvice{
@Override public
Void before ( method, object[] args, Object target) throws Throwable {
System.out.println ("Prehandle");}
}
Client.java public
class Client {public
static void main (String []args) {
ApplicationContext ac = new Cl Asspathxmlapplicationcontext ("Bean.xml");
Operateapi API = (OPERATEAPI) ac.getbean ("AOP");
Api.update ();
}
}
Output
prehandle
update
AOP Process
1. Generating proxy objects
The implementation of
Proxyfactorybean is the bottom-up approach to creating AOP in the spring IOC environment and is the most flexible approach. So through the use of Proxyfactorybean, look at the process of how AOP works.
Proxyfactorybean.java//Gets the generated proxy object public Object GetObject () throws Beansexception {Initializeadvisorchain ();
if (Issingleton ()) {return getsingletoninstance (); } else {if (this.targetname = = null) {Logger.warn ("Using Non-singleton proxies with Singleton targets is often undesirable.
"+" Enable prototype proxies by setting the ' TargetName ' property. ");
return Newprototypeinstance ();
}}//Create interceptor chain private synchronized void Initializeadvisorchain () throws Aopconfigexception, Beansexception {
If it has already been initialized, return directly if (this.advisorchaininitialized) {return; } if (! Objectutils.isempty (This.interceptornames)) {if (this.beanfactory = = null) {throw new Illega Lstateexception ("No beanfactory available anymore (probably due to serialization)" + "-cannot re SoLve Interceptor Names "+ arrays.aslist (this.interceptornames));
} if (This.interceptornames[this.interceptornames.length-1].endswith (global_suffix) && This.targetname = = NULL && This.targetsource = = Empty_target_source) {throw new Aopconfige
Xception ("Target required after Globals"); }//Traversal set interceptor for (String name:this.interceptorNames) {if (logger.istraceenabl
Ed ()) {logger.trace ("Configuring advisor or advice '" + name + "'"); } if (Name.endswith (Global_suffix)) {if (!) (
This.beanfactory instanceof Listablebeanfactory) {throw new Aopconfigexception (
"Can only use global advisors or interceptors with a listablebeanfactory");
}//Add all global interceptors, the main process is to find all the advisors and interceptor in Beanfactory, Added to Advisors addglobaladvisor ((listablebeanfactory) This.beanfactory,
Name.substring (0, Name.length ()-global_suffix.length ()));
} else {Object advice;
if (This.singleton | | This.beanFactory.isSingleton (name)) {//Pre-parsed from Beanfactory directly gets the object
Advice = This.beanFactory.getBean (name);
} else {advice = new prototypeplaceholderadvisor (name);
} addadvisoronchaincreation (advice, name);
}}} this.advisorchaininitialized = true; }//Add Interceptor private void Addadvisoronchaincreation (Object Next, String name) {//Convert the obtained class to advisor.
If it is advice, generate a new Advisor Advisor advisor with advice as a parameter = Namedbeantoadvisor (next);
if (logger.istraceenabled ()) { Logger.trace ("Adding Advisor with Name '" + name + "'");
} addadvisor (advisor);
}//Get singleton instance private synchronized Object getsingletoninstance () {if (this.singletoninstance = = null) {
Gets the instance according to the set TargetName and wraps it in Targetsource This.targetsource = Freshtargetsource ();
if (this.autodetectinterfaces && getproxiedinterfaces (). Length = = 0 &&!isproxytargetclass ()) {
Get Class class<?> Targetclass = Gettargetclass (); if (Targetclass = = null) {throw new Factorybeannotinitializedexception ("cannot determine target class
For proxy "); }//Get all the superclass interfaces and set to interface properties in Setinterfaces (Classutils.getallinterfacesforclass (targetclass, th
Is.proxyclassloader));
}//Initialize the shared singleton instance.
Super.setfrozen (This.freezeproxy);
Key to generating proxy instances This.singletoninstance = GetProxy (Createaopproxy ());
} return this.singletoninstance;
} Private synchronized Object newprototypeinstance () {//In the case of a prototype, we need to give the proxy
An independent instance of the configuration. In this case, no proxy would have a instance of this object's configuration,//But would have a independent co
Py.
if (logger.istraceenabled ()) {logger.trace ("Creating copy of Prototype Proxyfactorybean config:" + this);
} proxycreatorsupport copy = new Proxycreatorsupport (Getaopproxyfactory ());
The copy needs a fresh advisor chain, and a fresh targetsource.
Targetsource Targetsource = Freshtargetsource ();
Copy.copyconfigurationfrom (This, Targetsource, Freshadvisorchain ());
if (this.autodetectinterfaces && getproxiedinterfaces (). Length = = 0 &&!isproxytargetclass ()) { Rely onAOP infrastructure to the US what interfaces to proxy. Copy.setinterfaces (Classutils.getallinterfacesforclass (Targetsource.gettargetclass (), This.proxyClass
Loader));
} copy.setfrozen (This.freezeproxy);
if (logger.istraceenabled ()) {logger.trace ("Using proxycreatorsupport copy:" + copy);
} return GetProxy (Copy.createaopproxy ());
} Protected final synchronized Aopproxy Createaopproxy () {if (!this.active) {activate ();
} return Getaopproxyfactory (). Createaopproxy (this); }//Defaultaopproxyfactory.java @Override public aopproxy createaopproxy (advisedsupport config) throws Aopco nfigexception {if (config.isoptimize () | | | config.isproxytargetclass () | | | hasnousersuppliedproxyinterfaces (config)
) {class<?> Targetclass = Config.gettargetclass (); if (Targetclass = = null) {throw new AopconfigeXception ("Targetsource cannot determine target class:" + "either an interface or a target is requ
Ired for proxy creation. "); If it is an interface class or proxy class, use the JDK dynamic proxy if (Targetclass.isinterface () | | |
Proxy.isproxyclass (Targetclass)) {return new Jdkdynamicaopproxy (config);
} return new Objenesiscglibaopproxy (config);
} else {return new Jdkdynamicaopproxy (config); }}//Depending on what kind of proxy the aopporxy is, the method of generating the object is different protected object GetProxy (Aopproxy aopproxy) {return Aopproxy.getpro
XY (This.proxyclassloader); }
Advisorsupport.java//The main function of the following code is to add the acquired advisor to the advisors linked list, supplemented by clearing the cache @Override public void Addadvisor (Adviso
R Advisor) {int pos = this.advisors.size ();
Addadvisor (POS, advisor); } @Override public void addadvisor (int pos, advisor Advisor) throws Aopconfigexception {if (Advisor Inst
Anceof introductionadvisor) {validateintroductionadvisor (introductionadvisor) advisor);
} addadvisorinternal (POS, advisor); } private void Addadvisorinternal (int pos, advisor Advisor) throws Aopconfigexception {Assert.notnull (adviso
R, "Advisor must not is null");
if (IsFrozen ()) {throw new Aopconfigexception ("Cannot add advisor:configuration is frozen."); } if (pos > This.advisors.size ()) {throw new IllegalArgumentException ("Illega
L Position "+ pos +" in the Advisor list with size "+ this.advisors.size ()); } this.Advisors.add (POS, advisor);
Updateadvisorarray ();
Advicechanged ();
}/** * Bring the array up to date with the list. */protected final void Updateadvisorarray () {This.advisorarray = This.advisors.toArray (New Advisor[this.advi
Sors.size ()]);
} protected void Advicechanged () {this.methodCache.clear (); }
Here's how the JDK dynamic agent and Cglib dynamic agents generate proxy objects:
JDK Dynamic Agent
Public Object GetProxy (ClassLoader ClassLoader) {
if (logger.isdebugenabled ()) {
logger.debug ("Creating JDK Dynamic Proxy:target Source is "+ this.advised.getTargetSource ());
}
class<?>[] proxiedinterfaces = aopproxyutils.completeproxiedinterfaces (this.advised);
Finddefinedequalsandhashcodemethods (proxiedinterfaces);
Generates a proxy class by reflection based on the class loader and interface
return Proxy.newproxyinstance (ClassLoader, proxiedinterfaces, this);
}
cglib Dynamic Agent
Public Object GetProxy (ClassLoader ClassLoader) {if (logger.isdebugenabled ()) {Logger.debug ("Creating CGLIB
Proxy:target source is "+ this.advised.getTargetSource ());
} try {class<?> rootclass = This.advised.getTargetClass ();
Assert.state (Rootclass! = NULL, "Target class must is available for creating a CGLIB proxy");
class<?> proxysuperclass = Rootclass;
if (Classutils.iscglibproxyclass (Rootclass)) {Proxysuperclass = Rootclass.getsuperclass ();
class<?>[] additionalinterfaces = rootclass.getinterfaces (); for (class<?> additionalinterface:additionalinterfaces) {this.advised.addInterface (additionalinte
Rface);
}}//Validate the class, writing log messages as necessary.
Validateclassifnecessary (Proxysuperclass, ClassLoader);
Configure CGLIB Enhancer ...
Enhancer enhancer = Createenhancer (); if (ClassLoader! = null) {Enhancer.setclassloader (ClassLoader); if (ClassLoader instanceof smartclassloader && ((smartclassloader) classLoader). Isclassreloada
BLE (proxysuperclass)) {Enhancer.setusecache (false);
}} enhancer.setsuperclass (Proxysuperclass);
Enhancer.setinterfaces (Aopproxyutils.completeproxiedinterfaces (this.advised));
Enhancer.setnamingpolicy (springnamingpolicy.instance);
Enhancer.setstrategy (New Classloaderawareundeclaredthrowablestrategy (ClassLoader));
Callback[] callbacks = Getcallbacks (Rootclass);
class<?>[] types = new class<?>[callbacks.length];
for (int x = 0; x < types.length; × x + +) {Types[x] = Callbacks[x].getclass (); }//Fixedinterceptormap only populated at the "after Getcallbacks" call above ENHANCER.SETCALLBACKF
Ilter (New Proxycallbackfilter ( This.advised.getConfigurationOnlyCopy (), This.fixedinterceptormap, This.fixedinterceptoroffset));
Enhancer.setcallbacktypes (types);
Generate the proxy class and create a proxy instance.
return createproxyclassandinstance (enhancer, callbacks); } catch (Codegenerationexception ex) {throw new Aopconfigexception ("Could not generate CGLIB subclass of Clas s ["+ this.advised.getTargetClass () +"]: "+" Common causes of this problem include usin
G A final class or a non-visible class ", ex); } catch (IllegalArgumentException ex) {throw new Aopconfigexception ("Could not generate CGLIB subclass of CLA SS ["+ This.advised.getTargetClass () +"]: "+" Common causes of this problem include USI
Ng a final class or a non-visible class ", ex); } catch (Exception ex) {//Targetsource.gettarget () failed throw new AopconfigexCeption ("Unexpected AOP exception", ex); }
}
The above is the process of implementing the Build proxy object, and the interceptor's steps are the callbacks of the two proxies. Then the next step is to drill down to execute the callback code to achieve the Interceptor function. 2. Create an intercept chain
Take the JDK dynamic proxy callback as an example to see how to generate an intercept chain for the target object
The callback method of the JDK dynamic Agent @Override public object Invoke (object proxy, method, object[] args) throws Throwable {
Methodinvocation invocation;
Object oldproxy = null;
Boolean setproxycontext = false;
Gets the target proxy object Targetsource targetsource = This.advised.targetSource;
Class<?> targetclass = null;
Object target = null; try {if (!this.equalsdefined && Aoputils.isequalsmethod (method)) {//if the target class does not implement equal,
Implemented here.
Return equals (Args[0]); } if (!this.hashcodedefined && Aoputils.ishashcodemethod (method)) {//If Hashcode is not implemented (
) return hashcode ();
} if (!this.advised.opaque && method.getdeclaringclass (). Isinterface () && Method.getdeclaringclass (). IsAssignableFrom (Advised.class)) {//Call the method by reflection and execute return Aoputi Ls.invokejoinpoiNtusingreflection (this.advised, method, args);
} Object RetVal;
if (this.advised.exposeProxy) {//Make invocation available if necessary.
Oldproxy = Aopcontext.setcurrentproxy (proxy);
Setproxycontext = true; }//May is null.
Get as late as possible to minimize the time we ' own ' the target,//In case it comes from a pool.
target = Targetsource.gettarget ();
if (target! = null) {Targetclass = Target.getclass (); }//Here get the object all the Intercept chain list<object> chain = This.advised.getInterceptorsAndDynamicInterceptionAd
Vice (method, Targetclass); If there is no intercept chain, or if there is no corresponding enhanced if (Chain.isempty ()) {//directly using reflection to execute Object method object[] Argstous
E = Aopproxyutils.adaptargumentsifnecessary (method, args); RetVal = aoputils.invokejoinpointusingreflection (tArget, method, Argstouse); } else {//otherwise new reflectivemethodinvocation, followed by the method of intercepting chain invocation = new Reflect
Ivemethodinvocation (proxy, Target, method, args, Targetclass, chain);
Proceed to the Joinpoint through the interceptor chain.
RetVal = Invocation.proceed ();
}//Massage return value if necessary.
class<?> returntype = Method.getreturntype (); if (retVal! = null && RetVal = = Target && returntype.isinstance (proxy) &&! RawTargetAccess.class.isAssignableFrom (Method.getdeclaringclass ())) {//Special case:it returned "this" And the return type of the method//Is type-compatible.
Note that we can ' t help if the target sets//a reference to itself in another returned object.
RetVal = proxy; } else if (RetVal = = nulL && returntype! = Void.type && returntype.isprimitive ()) {throw new Aopinvocationexcepti
On ("Null return value from advice does not match primitive return type for:" + method);
} return retVal; } finally {if