I’ve written a lot of articles, and I’ve been getting so-so reviews (but I feel like I’ve done my best work), so it’s time to change up my writing skills and hopefully get the most out of them in a fun way. Previously written articles directly on the source code analysis, this will let people do not understand looking very tired, not the desired effect. This article from the background – principle – use – source order for you to analyze. If you don’t want to go deeper, it’s enough to see the “use” level. Hope you enjoy reading this article and give some feedback

A, AOP

Background to AOP

“Existence is reasonable”, any kind of theory or technology, there must be its reasons. Understanding the context in which it arose and the problems it was designed to solve helps us better grasp the concept of AOP. Software development is always looking for a way to develop, protect and maintain efficiently. From the practice of process-oriented development, predecessors abstracted the concerns, aggregated the behaviors and attributes, and formed the idea of object-oriented development, which affected the process of software development to a certain extent. For this reason, software development is abstracted and divided into modules or objects during development. For example, we will to abstract API into four modules: the Controller, the Service, the Gateway, the Command. This addresses business-level development nicely, but it’s hard to focus on system-level development. For example, for each module needs to log, code monitoring, exception handling. In the case of logging, FOR example, I can only nest the logging code on the objects and can’t focus on the logging itself, which is a deviation from OOP thinking.






1.2 Members of the AOP family

1.2.1 PointCut

That is, where to cut in, it can specify a point, or it can specify multiple points. Like the Methord function of class A, of course, generic AOP and languages (AOL) define PointCut in multi-purpose ways, such as regular expressions that specify multiple functions of multiple classes at the same time.

1.2.2 Advice

What to do at pointcuts, specify what to do at pointcuts (enhancements), log, perform caching, handle exceptions, and so on.

1.2.3 Advisor/Aspect

PointCut + Advice forms the Aspect, and the concept itself represents all the elements of the Aspect. But it’s not complete at this point, because we don’t know how to embed aspects into the code, and the technology that solves this problem is PROXY, right

1. The Proxy

A Proxy is a Proxy that is not considered a member of AOP’s family, but rather a governing body that governs how AOP fits into OOP. The reason why it is put here is that although Aspect is an important part of the section-oriented core idea, the implementer of its idea is Proxy, which is also the difficulty and core basis of implementing AOP.

Second, AOP technology to implement Proxy

AOP is just an idea, that in order to let this idea shine, it is necessary to separate from the language itself technology support, Java in the implementation of the technology is the use of Proxy Proxy, then we go to understand, how to achieve through Proxy face cutting

1. Static proxy








public interface IPerson {
    public void doSomething();
}Copy the code
public class Person implements IPerson {
    public void doSomething(){
        System.out.println("I want wo sell this house"); }}Copy the code

public class PersonProxy {
    private IPerson iPerson;
    private final static Logger logger = LoggerFactory.getLogger(PersonProxy.class);

    public PersonProxy(IPerson iPerson) {
        this.iPerson = iPerson;
    }
    public void doSomething() {
        logger.info("Before Proxy");
        iPerson.doSomething();
        logger.info("After Proxy");
    }

    public static void main(String[] args) {
        PersonProxy personProxy = new PersonProxy(newPerson()); personProxy.doSomething(); }}Copy the code

Through a proxy class we implemented to integrate the logging code to the target class, but from the above we can see that it has significant limitations: need fixed class write interface (maybe also can accept, after all, have advocated programming to an interface), the need to implement the each function of the interface (unacceptable), can also cause a large number of repeat code, will make the code more chaos.

2. Dynamic proxy

Is it possible to weave Logger into all functions just by implementing the code once? Of course it is, using the reflection mechanism in Java


public class PersonProxy implements InvocationHandler{
    private Object delegate;
    private final Logger logger = LoggerFactory.getLogger(this.getClass();

    public Object bind(Object delegate) {
        this.delegate = delegate;
        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
            logger.info("Before Proxy");
            result = method.invoke(delegate, args);
            logger.info("After Proxy");
        } catch (Exception e) {
            throw e;
        }
        return result;
    }

    public static void main(String[] args) {
        PersonProxy personProxy = new PersonProxy();
        IPerson iperson = (IPerson) personProxy.bind(newPerson()); iperson.doSomething(); }}Copy the code

It is handy to generate proxy classes for any interface and weave enhanced methods into any object function. However, it still has the limitation that only classes that implement the interface can be proxying for them.

3.CGLIB

CGLIB solves the problem of dynamic proxies by generating subclasses of the target class to implement proxies rather than interfaces, avoiding the limitations of interfaces. CGLIB is a powerful high-performance code generation package (the principles of which have not yet been explored) that subclasses the prosted-object at run time (non-compile time) and overwrites all the methods of the prosted-object as a prosted-object.

public class PersonProxy implements MethodInterceptor {
    private Object delegate;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public Object intercept(Object proxy, Method method, Object[] args,  MethodProxy methodProxy) throws Throwable {
        logger.info("Before Proxy");
        Object result = methodProxy.invokeSuper(method, args);
        logger.info("After Proxy");
        return result;
    }

    public static Person getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Person.class);

        enhancer.setCallback(new PersonProxy());
        return(Person) enhancer.create(); }}Copy the code

CGLIB also has limitations. There is no way to subclass a final class that cannot be subclassed.

These are the three proxy implementations, but don’t be fooled; in Spring AOP these are already packaged and don’t need to be implemented ourselves. It’s exhausting to do otherwise, but it’s important to understand how AOP works (that is, proxy-based).

Three, the application

First build a target class (this class I myself are disgusting), or sell the house, discuss the price, directly write dead, meaning meaning……

public class Person {
    public int tradePrice () {
        return 1000; }}Copy the code

MethodInteceptor to implement an Advisor, MethodInteceptor to implement an Advisor, MethodInteceptor to implement an Advisor

public class LogsInterceptor implements MethodInterceptor {
    Logger logger = LoggerFactory.getLogger(this.getClass().getName());
    public Object invoke(MethodInvocation invocation) throws Throwable {
        try {
            logger.info("Start bargaining....");
            Object returnValue = invocation.proceed();
        } catch (Exception e) {
            throw e;
        } finally {
            logger.info("Bargaining Over");
        }
        return null; }}Copy the code

3.1. Configure ProxyFactoryBean to explicitly set pointCut, Advice, and Advisor

It is ok to configure one by one, although such trouble, but you know principle……


<bean id="pointCut" class="org.springframework.aop.support.NameMatchMethodPointcut">
    <property name="mappedName" value="tradePrice"/>
</bean>
<bean id="myInterceptor" class="com.sankuai.meituan.meishi.poi.tag.LogsInterceptor"></bean>
<bean id="myAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    <property name="pointcut" ref="pointCut"/>
    <property name="advice" ref="myInterceptor"/>
</bean>
<bean id="myProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
        </list>
    </property>
</bean>Copy the code

But the gross part is that you have to define advisor one by one. If you have several target pointcuts, you have to define them several times

3.2. Configure AutoxyCreator. In this way, we still use defined beans as before, but we get proxy objects from the container

In order to solve the above problem AutoProxyCreator has two concrete implementation class BeanNameAutoProxyCreator and DefaultAdvisorAutoProxyCreator, first take a headphones

<bean id="pointCut1" class="org.springframework.aop.support.NameMatchMethodPointcut">
    <property name="mappedName" value="tradePrice"/>
</bean>
<bean id="pointCut2" class="org.springframework.aop.support.NameMatchMethodPointcut">
    <property name="mappedName" value="tradePrice"/>
</bean>
<bean id="myInterceptor" class="com.sankuai.meituan.meishi.poi.tag.LogsInterceptor"></bean>

<bean id="myProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
        <list>
            <value>pointCut1</value>
            <value>pointCut2</value>
        </list>
    </property>
    <property name="interceptorNames">
        <list>
            <value>myInterceptor</value>
        </list>
    </property>
</bean>Copy the code

Does it feel better, but people don’t like to write about it (though I still recommend this configuration)

3.3. Configure via AOP :config

We refer to it, not recommended

3.4. Use AspectJ annotations to identify advice and pointcuts by configuring

The introduction of AspectJ can be implemented with aspect annotations, which are only concerned with the aspect itself


public class MyAspect {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("execution(public void *.method1)")
    public void pointcutName(){}

    @Around("pointcutName()")
    public Object performanceTrace(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try {
            logger.info("log.....");
            return proceedingJoinPoint.proceed();

        } finally {
            logger.info("log end"); }}}Copy the code

Proxy generation of facets depends on it…

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>Copy the code

Aspectj is very powerful, and its defining syntax and operations are beyond the focus of this article

Fourth, in-depth analysis

Spring AOP is AOL family Loser is also the winner, follow the road to the simple. Spring AOP only supports some of the functions of AOP, as a lightweight framework, the implementation of AOP20% of the technology, support 80% of the requirements, although the integration of AspectJ, but its internal principle is still used is Spring AOP, so it can only use AspectJ part of the function.

4.1 Members of Spring Aop’s family

The following is only for Spring Aop, not other AOls (Spring Aop is much simpler than other Aols, but there is support for other Aols as well)

4.1.1 PointCut








public abstract class StaticMethodMatcher implements MethodMatcher {

   @Override
   public final boolean isRuntime() {
      return false; } @Override public final boolean matches(Method method, Class<? > targetClass,Object[] args) {
      // should never be invoked because isRuntime() returns false
      throw new UnsupportedOperationException("Illegal MethodMatcher usage"); }}Copy the code

public abstract class DynamicMethodMatcher implements MethodMatcher {

   @Override
   public final boolean isRuntime() {
      return true;
   }

   /** * Can override to add preconditions for dynamic matching. This implementation * always returns true. */@Override public boolean matches(Method method, Class<? > targetClass) {return true; }}Copy the code

Similar to inherit from StaticMethodMatcher and DynamicMethodMatcher also have two branch StaticMethodMatcherPointcut and DynamicMethodMatcherPointcut, StaticMethodMatcherPointcut is our most commonly used, and the concrete implementation, there are two NameMatchMethodPointcut and JdkRegexpMethodPointcut, a matching by name, one by a regular expression match. It’s worth mentioning another branch, the ExpressionPointcut, which appears as support for AspectJ, So their concrete implementations have AspectJExpressionPointcut is on the left side of the three offers us a stronger function of PointCut AnnotationMatchingPointcut: you can specify certain types of annotation ControlFlowPointcut: This is A bit special, it is A control flow, such as the class A call b.thod (), which can specify that it is intercepted only when called by A.

3.1.2 Advice

Let’s look at the Advice class diagram, starting with the interface classification:


3.1.3 Advisor

An Advice Advisor can also be a bit of a Spring AOP Interceptoor an AOP alliance Interceptoor, an inheritance and implementation of a MethodInterceptor





AbstractPointcutAdvisor implements Ordered for multiple Advice specified order, the order of type Int, the smaller the higher priority, AbstractGenericPointcutAdvisor specifies the Advice, The following Advisor implementations correspond to the type of the PointCut, specifying which PointCut,

The Introduction type, which is basically similar to the above, will not be introduced

3.1.4 Proxy

This section is the key, and it determines how to implement AOP in detail, so this section is going to be a little harder to understand. Let’s take a look at the class diagram


private boolean proxyTargetClass = false;

private boolean optimize = false;

boolean opaque = false;

boolean exposeProxy = false;

private boolean frozen = false;Copy the code

private boolean proxyTargetClass = false; There are two types of proxy: interface proxy (the dynamic proxy mentioned above) and CGLIB. By default, classes with interfaces use the interface proxy; otherwise, CGLIB is used. If set to true, CGLIB is used directly. The original notes are as follows


/** * Set whether to proxy the target class directly, instead of just proxying * specific interfaces. Default is "false". * 

Set this to "true" to force proxying for the TargetSource's exposed * target class. If that target class is an interface, a JDK proxy will be * created for the given interface. If that target class is any other class, * a CGLIB proxy will be created for the given class. *

Note: Depending on the configuration of the concrete proxy factory, * the proxy-target-class behavior will also be applied if no interfaces * have been specified (and no interface autodetection is activated). * @see org.springframework.aop.TargetSource#getTargetClass() */

Copy the code

private boolean optimize = false; Whether or not to optimize is generally different for different agents. If the proxy object is generated, changes to the Advised object are ignored.


/** * Set whether proxies should perform aggressive optimizations. * The exact meaning of "aggressive optimizations" will differ * between proxies, but there is usually some tradeoff. * Default is "false". * 

For example, optimization will usually mean that advice changes won't * take effect after a proxy has been created. For this reason, optimization * is disabled by default. An optimize value of "true" may be ignored * if other settings preclude optimization: for example, if "exposeProxy" * is set to "true" and that's not compatible with the optimization. */

Copy the code

Whether Opaque is forced to convert to the advised


/** * Set whether proxies created by this configuration should be prevented * from being cast to {@link Advised} to query proxy status. * 

Default is "false", meaning that any AOP proxy can be cast to * {@link Advised}. */

Copy the code

ExposeProxy: When AOP generates an object, it is bound to ThreadLocal and can be obtained through AopContext

 /** * Set whether the proxy should be exposed by the AOP framework as a * ThreadLocal for retrieval via the AopContext class. This is useful * if an advised object needs to call another advised method on itself. * (If it uses {@code this},  the invocation will not be advised). * 

Default is "false", in order to avoid unnecessary extra interception. * This means that no guarantees are provided that AopContext access will * work consistently within any method of the advised object. */

Copy the code

Frozen: Indicates whether the agent information can be changed once it is set

/** * Set whether this config should be frozen. * 

When a config is frozen, no advice changes can be made. This is * useful for optimization, and useful when we don't want callers to * be able to manipulate configuration after casting to Advised. */

Copy the code

AdvisedSupport sets all the information needed to generate the proxy object.

ProxyCreatorSupport does the work of generating agents. As for what they do, I won’t go into detail here because there are a lot of things to do. Different Advisors and Pointcuts encapsulate their actions differently. It’s easy to read the source code when you use them.

5. Best practices

So when to use AOP? I’ll define it myself: AOP should be used to decouple a function from an object when it has no necessary relationship to the object itself and occurs repeatedly in multiple modules. Someone summed up the usage scenario (refer, agree or disagree) : Authentication permission Caching Context passing Passing Error handling Lazy loading Debugging logging, tracing, tracing, tracing Profiling and monitoring Optimization calibration Performance optimization Persistence Resource pooling Synchronization Synchronizes Transactions

5.1 log

I’ve read a lot about logging as an example of AOP, which is actually not very good because AOP is difficult to fully implement log behavior, but it’s useful for some types of logging processing. For example, to uniformly handle Command exceptions and log requests at the Controller layer, see github.com/ameizi/DevA…

5.2 Code performance test

Use PerformanceMonitorInterceptor to assist application performance optimization, spring’s own

www.cnblogs.com/f1194361820… And of course the JamonPerformanceMonitorInterceptor