Source: It family release time: 2011-03-22 20:28 read: 3,546 recommendations: 2 original link [favorites]
Abstract: This article is mainly to explain the development of application system in. NET language in the implementation of AOP.
The article mainly explains the development of the application system when you are in. NET language in the implementation of AOP. The main function of Logaspect is to map the advice with the method of the business object and add it to the advice collection. Since we are using an XML configuration file to configure Pointcut in the AOP implementation, these operations are the same for all aspect, as long as the correct configuration file is defined and read in. For Aspect's SyncProcessMessage (), because the interception and weaving method is the same, the difference is only advice logic, so in all aspect common base class has provided the default implementation:
public class Logaspect:aspect
{
Public Logaspect (IMessageSink nextsink): Base (Nextsink)
{}
}
Then define the correct configuration file:
<aspect value = "LOGAOP" >
<advice type= "Before" assembly= "AOP. Advice "class=" AOP. Advice.logadvice ">
<pointcut>ADD</pointcut>
<pointcut>SUBSTRACT</pointcut>
</advice>
<advice type= "after" assembly= "AOP. Advice "class=" AOP. Advice.logadvice ">
<pointcut>ADD</pointcut>
<pointcut>SUBSTRACT</pointcut>
</advice>
</aspect>
The assembly file that the logadvice belongs to is AOP.Advice.dll, and the complete class name is AOP.Advice.LogAdvice.
Log advice (Logadvice)
Because the log aspect needs to record related data before and after the method call, Logadvice should implement both Ibeforeadvice and Iafteradvice interfaces:
public class Logadvice:iafteradvice,ibeforeadvice
{
#region Ibeforeadvice Members
public void Beforeadvice (IMethodCallMessage callmsg)
{
if (callmsg = = null)
{
Return
}
Console.WriteLine ("{0} ({1},{2})",
Callmsg.methodname, Callmsg.getarg (0),
Callmsg.getarg (1));
}
#endregion
#region Iafteradvice Members
public void Afteradvice (IMethodReturnMessage returnmsg)
{
if (returnmsg = = null)
{
Return
}
Console.WriteLine ("Result is {0}", Returnmsg.returnvalue);
}
#endregion
}
In the Beforeadvice () method, the message type is IMethodCallMessage, and through this interface object, you get the parameter values for the method name and the method call. In contrast, the message type in the Afteradvice () method is imethodreturnmessage,advice the data to be obtained is the return value returnvalue of the method.
Performance monitoring aspects
Performance monitoring is much the same as logging implementations, and for simplicity, the performance monitoring I want to implement is just the time before and after the method call is recorded.
Performance monitoring attribute (Monitoraopattribute)
As with the log attribute, Monitoraopattribute simply needs to create and return the corresponding Monitoraopproperty object:
[AttributeUsage (AttributeTargets.Class)]
public class Monitoraopattribute:aopattribute
{
Public Monitoraopattribute (): Base ()
{}
Public Monitoraopattribute (String aspectxml): Base (Aspectxml)
{}
protected override Aopproperty Getaopproperty ()
{
return new Monitoraopproperty ();
}
}
Performance Monitoring Property (Monitoraopproperty)
The Monitoraopproperty property name is defined as MONITORAOP, which distinguishes it from the log-related attributes. In addition to defining property names for performance monitoring, you need to override the Createaspect () method to create and return the corresponding facet object monitoraspect:
public class Monitoraopproperty:aopproperty
{
protected override IMessageSink Createaspect
(IMessageSink Nextsink)
{
return new Monitoraspect (Nextsink);
}
protected override string GetName ()
{
return "MONITORAOP";
}
}
4.4.2.3 Performance monitoring aspect (Monitoraspect)
The implementation of the Monitoraspect class is also simple:
public class Monitoraspect:aspect
{
Public Monitoraspect (IMessageSink nextsink): Base (Nextsink)
{}
}
The definition of its configuration file is as follows:
<aspect value = "MONITORAOP" >
<advice type= "Before" assembly= "AOP. Advice "
Class= "AOP. Advice.monitoradvice ">
<pointcut>ADD</pointcut>
<pointcut>SUBSTRACT</pointcut>
</advice>
<advice type= "after" assembly= "AOP. Advice "
Class= "AOP. Advice.monitoradvice ">
<pointcut>ADD</pointcut>
<pointcut>SUBSTRACT</pointcut>
</advice>
</aspect>
The assembly file that the monitoradvice belongs to is AOP.Advice.dll, and the complete class name is AOP.Advice.MonitorAdvice.
Performance monitoring Advice (Monitoradvice)
Because performance monitoring requires recording the specific time before and after the method call, the Monitoradvice should implement both the Ibeforeadvice and Iafteradvice interfaces:
public class Monitoradvice:ibeforeadvice, Iafteradvice
{
#region Ibeforeadvice Members
public void Beforeadvice (IMethodCallMessage callmsg)
{
if (callmsg = = null)
{
Return
}
Console.WriteLine ("Before {0} at {1}",
Callmsg.methodname, DateTime.Now);
}
#endregion
#region Iafteradvice Members
public void Afteradvice (IMethodReturnMessage returnmsg)
{
if (returnmsg = = null)
{
Return
}
Console.WriteLine ("After {0} at {1}",
Returnmsg.methodname, DateTime.Now);
}
#endregion
}
Monitoradvice only needs to record the time before and after the method call, so it is only necessary to record the current time in the Beforeadvice () and Afteradvice () methods respectively.
Business Objects and applications
Business Object (Calculator)
With AOP technology, we have completely separated our core concerns from crosscutting concerns, and we don't need to focus on including logs, performance monitoring, etc. when defining business objects, which is also an advantage of AOP technology. Of course, due to use. Net of attribute and agent technology, for the application of the aspect of business objects, still need some small restrictions.
First of all, we should apply the defined aspects aspect to the business object. Second, because the agent technology wants to get the context of the business object, the context must be specified rather than the default context. The context is obtained when the business object is created and invoked, and if it is to get the specified context, in. NET, the business object must inherit the ContextBoundObject class.
Therefore, the definition of the last business object Calculator class is as follows:
[MONITORAOP]
[LOGAOP]
public class Calculator:contextboundobject
{
public int Add (int x,int y)
{
return x + y;
}
public int substract (int x,int y)
{
return x-y;
}
}
[MONITORAOP] and [LOGAOP] are precisely the previously defined aspect attribute, in addition Calculator class inherits ContextBoundObject. In addition, the definition of the calculator class is the same as the normal object definition. However, using AOP technology, it is possible to intercept the Add () and Substract () Methods of the Calculator class for logging and performance monitoring. The implementation of the logic code for logging and performance monitoring is completely separate from the Add () and Substract () Methods of the Calculator class, which realizes the cancellation of the dependencies and facilitates the reuse and expansion of the modules.
Application (Program)
We can implement a simple application to see how the business object Calculator The effects of logging and performance testing:
Class Program
{
[STAThread]
static void Main (string[] args)
{
Calculator cal = new Calculator ();
Cal. ADD (3,5);
Cal. Substract (3,5);
Console.ReadLine ();
}
}
The program creates a calculator object and calls the Add () and Substract () methods. Because the Calculator object is applied to both the logging aspect and the performance detection aspect, the run result prints the details of the method call and the current time before and after the call.
If you want to change the way logging and performance monitoring results are written, such as writing them to a file, you only need to change the implementation of Logadvice and Monitoradvice, and for Calculator objects, you don't need to make any changes.
In the implementation of AOP in. NET I have basically implemented several technical elements of AOP, including aspect,advice,pointcut, through dynamic proxy technology. At the end of the article I mentioned using the configuration file method to get the mapping between advice and pointcut, so that the building aspect is extensible.
Pondering this question, I find it is not a sensible choice to use delegate to build advice. When I establish a mapping relationship, it is the method name that will be intercepted and the aspect logic that intercepts need to implement to establish a correspondence, and the aspect logic can indeed pass delegate to point to a family of methods that the signature of a method exactly matches that delegate. This allows the advice to be abstracted in order to facilitate the implementation of the specific extension. However, the Commission of its implementation is, after all, a process-oriented category, albeit in. NET, delegate itself is still a class object, but it is still difficult to get through configuration files and reflection techniques when creating concrete delegate instances.
Given the nature of the interface abstraction that a delegate has, it may be more feasible to replace the delegate with an interface. In the previous implementation scenario, I defined two delegates for advice:
public delegate void Beforeaophandle (IMethodCallMessage callmsg);
public delegate void Afteraophandle (IMethodReturnMessage replymsg);
I can define two interfaces, Ibeforeaction and iafteraction, that correspond to the two delegates:
public interface Ibeforeadvice
{
void Beforeadvice (IMethodCallMessage callmsg);
}
public interface Iafteradvice
{
void Afteradvice (IMethodReturnMessage returnmsg);
}
By defining the interface, the advice can be separated from the aspect, which is in line with the principle of "separation of responsibilities" in Oo thought.
(Note: Why do I need to define two interfaces for advice?) It is considered that some aspect only need to provide one of the before or after two logic, such as permission control, just need to before Action. )
Then when the class library consumer, to define their own aspect, you can define the specific advice class, to implement the two interfaces, as well as the specific advice logic. For example, the previously mentioned log aspect:
public class Logadvice:iafteradvice,ibeforeadvice
{
#region Ibeforeadvice Members
public void Beforeadvice (IMethodCallMessage callmsg)
{
if (callmsg = = null)
{
Return
}
Console.WriteLine ("{0} ({1},{2})",
Callmsg.methodname, Callmsg.getarg (0),
Callmsg.getarg (1));
}
#endregion
#region Iafteradvice Members
public void Afteradvice (IMethodReturnMessage returnmsg)
{
if (returnmsg = = null)
{
Return
}
Console.WriteLine ("Result is {0}", Returnmsg.returnvalue);
}
#endregion
}
In a derived class of the Aopsink class, you can add class objects that implement the advice interface when you add the method name to the advice mapping relationship (which we can understand as an AOP pointcut), such as:
public override void Addallbeforeadvices ()
{
Addbeforeadvice ("ADD", New Logadvice ());
Addbeforeadvice ("Substract", New Logadvice ());
}
public override void Addallafteradvices ()
{
Addafteradvice ("ADD", New Logadvice ());
Addafteradvice ("Substract", New Logadvice ());
}
Because the Logadvice class implements interface Ibeforeadvice and Iafteradvice, operations such as new Logadvice can be created with reflection to create the instance, such as:
Ibeforeadvice Beforeadvice =
(Ibeforeadvice) Activator.CreateInstance ("Wayfarer.aopsample", "Wayfarer.AOPSample.LogAdvice"). Unwrap ();
The parameter values of the CreateInstance () method are fully configurable through the configuration file:
<aop>
<aspect value = "LOG" >
<advice type= "Before" assembly= "Wayfarer.aopsample" class= "Wayfarer.AOPSample.LogAdvice" >
<pointcut>ADDpointcut>
<pointcut>SUBSTRACTpointcut>
Advice>
<advice type= "after" assembly= "Wayfarer.aopsample" class= "Wayfarer.AOPSample.LogAdvice" >
<pointcut>ADDpointcut>
<pointcut>SUBSTRACTpointcut>
Advice>
Aspect>
Aop>
This undoubtedly improves the extensibility of AOP implementations.
The realization of AOP in. NET implements the AOP scheme, which requires that the class containing the intercepted method must inherit ContextBoundObject. This is a relatively large limit. Not only that, ContextBoundObject also has a great influence on the performance of the program. We can do a little test. Defines two classes in which one class inherits ContextBoundObject. They all implement an additive operation:
Class Normalobject
{
public void Sum (int n)
{
int sum = 0;
for (int i = 1; I <= n; i++)
{
sum + = i;
}
Console.WriteLine ("The result is {0}", sum);
Thread.Sleep (10);
}
}
Class Marshalobject:contextboundobject
{
public void Sum (int n)
{
int sum = 0;
for (int i = 1; I <= n; i++)
{
sum + = i;
}
Console.WriteLine ("The result is {0}", sum);
Thread.Sleep (10);
}
}
Then execute the sum () method of the two classes to test its performance:
Class Program
{
static void Main (string[] args)
{
Long NORMALOBJMS, MARSHALOBJMS;
Stopwatch watch = new Stopwatch ();
Normalobject no = new Normalobject ();
MarshalObject mo = new MarshalObject ();
Watch. Start ();
No. Sum (1000000);
Watch. Stop ();
NORMALOBJMS = watch. Elapsedmilliseconds;
Watch. Reset ();
Watch. Start ();
Mo. Sum (1000000);
Watch. Stop ();
MARSHALOBJMS = watch. Elapsedmilliseconds;
Watch. Reset ();
Console.WriteLine ("The normal object consume
{0} milliseconds. ", NORMALOBJMS);
Console.WriteLine ("The Contextbound object consume {0} milliseconds.", MARSHALOBJMS);
Console.ReadLine ();
}
}
The results are as follows:
From the differences in performance, the gap between the two is relatively large. If you apply it to complex logic at the enterprise level, the difference is obvious and the impact on the system is enormous.
In addition, after the article on the implementation of AOP in. NET, some friends made a lot of pertinent comments. Some of them mentioned the question of Aopattribute inheriting ContextAttribute. It is mentioned in the comments that Microsoft will no longer provide contextattribute in future releases. If so, it is necessary to abandon the form of inheriting ContextAttribute. However, in. NET, in addition to ContextAttribute, there is an interface Icontextattribute, which is defined as:
public interface Icontextattribute
{
void Getpropertiesfornewcontext (IConstructionCallMessage msg);
BOOL Iscontextok (Context CTX, IConstructionCallMessage msg);
}
At this point only the original Aopattribute implementation of the interface can be:
Public abstract class Aopattribute:attribute,
Icontextattribute//contextattribute
{
#region Icontextattribute Members
public void Getpropertiesfornewcontext
(IConstructionCallMessage ctormsg)
{
Aopproperty property = Getaopproperty ();
Property. Aspectxml = M_aspectxml;
Property. Aspectxmlflag = M_aspectxmlflag;
CtorMsg.ContextProperties.Add (property);
}
public bool Iscontextok (Context CTX,
IConstructionCallMessage ctormsg)
{
return false;
}
#endregion
}
Do not know, Icontextattribute seems to be in the future version will be canceled?
However, in general, this way of using ContextBoundObject is not ideal, perhaps it can only stay in the laboratory stage, may expect Microsoft in the future version to be better solved!
Of course, if the use of Castle Dynamicproxy technology, you can break the limitations must inherit cotextboundobject, but with the limitation is the method of AOP interception, the requirements must be virtual. Frankly speaking, such restrictions, but the former is a "kettle black" difference. I'm still looking forward to a better solution.
When it comes to the major elements of AOP, it can be added here that it mainly includes:
1, cross-cutting concern
In the OO model, although most classes have only a single, specific function, they often have a second requirement in common with other classes. For example, when a thread enters or leaves a method, we may want to both log in the class of the data access layer and log in the class in the UI layer. Although the basic functionality of each class is extremely different, the code used to satisfy the second requirement is essentially the same.
2, Advice
It refers to additional code that you want to apply to an existing model. For example, in the example "Implementation of AOP in. Net", it refers to the logical code for printing logs.
3, Point-cut
This term refers to an execution point in the application that requires the previous cross-cutting concern to be used on this execution point. In the example, an point-cut occurs when the Add () method is executed, and another point-cut occurs when the method executes and leaves the method.
4, Aspect
The combination of point-cut and advice is called aspect. such as the log and monitor in the example. In the reconstruction of this example, I have aopsink renamed to Aspect, the corresponding Logaopsink, Monitoraopsink also renamed to Logaspect,monitoraspect.
The above mentioned pointcut and advice are commonly referred to as dynamic crosscutting techniques in AOP techniques. Corresponding to this, is less mentioned static crosscutting. It differs from dynamic crosscutting in that it does not modify the execution behavior of a given object, but instead allows you to modify the inherent structure of an object by introducing additional method properties and fields. In many AOP implementations, static crosscutting is referred to as introduce or mixin.
In the development of the application system, if you need to not modify the original code, the introduction of third-party products and API library, static crosscutting technology has a great use. From this point of view, it is somewhat similar to the adapter pattern mentioned in the design pattern that needs to be achieved. However, it seems that static crosscutting techniques should be more flexible and powerful than the adapter model.
For example, a class mail has been implemented to send and receive mail. However, it does not implement the function of address verification. Now the third party provides the interface for the authentication function ivalidatable:
public interface Ivalidatable
{
BOOL Validateaddress ();
}
If there is no AOP, in the way of design pattern, without changing the mail class, we can introduce Mailadater, inherit the mail class and implement Ivalidatable interface by adapter mode. With introduce technology, it is easier to implement the extension of this function, we only need to define aspect: (Note: Java code, using the ASPECTJ)
Import com.acme.validate.Validatable;
Public Aspect Emailvalidateaspect
{
Declare Parents:email implements Ivalidatable;
public Boolean email.validateaddress () {
if (this.gettoaddress () = null) {
return true;
}else{
return false;
}
}
}
From the above can be seen, through the emailvalidateaspect aspect, for the e-mail class introduce a new method Validateaddress (). It is very easy to complete the extension of the email.
We can compare, if using adapter mode, the original email class can not be displayed to the Ivalidatable interface, that is to say the following code is not feasible:
Email mail = new email ();
Ivalidatable validate = ((ivalidatable) mail). Validateaddress ();
To invoke the Validateaddress () method, you must pass the EmailAdapter class. With static crosscutting techniques, however, the above code is entirely feasible.
. The implementation of AOP in the net language