Popular Science: Spring underlying introduced enhancements (IntroductionAdvice) implementation principle

There are five reinforcing Spring: BeforeAdvide (pre-enhancement), AfterAdvice (rear enhancement), ThrowsAdvice (abnormal enhancement), RoundAdvice (surround enhancement), IntroductionAdvice (incorporated enhancement)

RoundAdvice (Enhanced Surround): is BeforeAdvide (pre-enhancement), a combination AfterAdvice (post-boost) is called using the surround enhancement.

The first four enhancements are relatively simple, we have to introduce the concept and principle IntroductionAdvice (introduced enhanced) of.

Introducing the concept of enhanced (Introduction Advice) to: a Java class does not implement the A interface, without modifying Java class, it has a function of A interface.

1.Cglib achieve the introduction of enhanced

Remember, my purpose is not to tell you how to use enhancements introduced in Spring (This is not my style), but rather to explore the introduction of enhanced features to achieve the underlying principle.

public interface IHello {

    public void sayHello();
}

The above is an interface function, is the need to enhance CeremonyService classes, without changing CeremonyService class, it has IHello interface function.

public class CeremenyService {

    public void sayBye() {
        System.out.println("Say bye from Ceremeny.");
    }

}

To look like this:

CeremenyService cs;

IHello ih = (IHello) cs;
ih.sayHello();

That is, CeremenyService actually turned into IHello type.

We write an important interceptors to implement this feature.

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import x.y.IHello;

public class IntroInterceptor implements MethodInterceptor, IHello {
        // 实现了IHello增强接口的对象
    private Object delegate;

    public IntroInterceptor() {
        this.delegate = this;
    }

    public IntroInterceptor(Object delegate) {
        this.delegate = delegate;
    }

    @Override
    public void sayHello() {
        System.out.println("Say hello from delegate.");
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Class<?> clz = method.getDeclaringClass();
        if (clz.isAssignableFrom(IHello.class)) {
                // 如果实现了IHello增强接口,则调用实现类delegate的方法
            return method.invoke(delegate, args);
        }
        return methodProxy.invokeSuper(obj, args);
    }
}

Let's write a test class.

public static void main(String[] args) {
    Enhancer en = new Enhancer();
    en.setSuperclass(CeremenyService.class);
    en.setInterfaces(new Class[] { IHello.class });
    en.setCallback(new IntroInterceptor());

    CeremenyService cs = (CeremenyService) en.create();
    cs.sayBye();

    IHello ih = (IHello) cs;
    ih.sayHello();
}

en.setInterfaces (new Class [] {IHello.class}); important, it represents Cglib generated proxy class, set the interface to be achieved.

Thus generated proxy class Class, like:public class CeremenyService$$EnhancerByCGLIB$$86859be5 extends CeremenyService implements IHello

Output:

Say bye from Ceremeny.
Say hello from delegate.

This is the bottom of the famous introduction of enhanced (Introduction Advice) implementation principle.

2. Spring framework introduced enhanced source code interpretation

Spring's xml configuration file.

<bean id="ceremonyService" class="x.y.service.CeremonyService" />
<bean id="ceremonyIntroAdvice" class="x.y.advice.CeremonyIntroAdvice" />

<bean id="ceremonyProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interfaces" value="x.y.IHello"/>                   <!-- 需要动态实现的接口 -->
        <property name="target" ref="ceremonyService"/>                    <!-- 目标类 -->
        <property name="interceptorNames" value="ceremonyIntroAdvice"/>    <!-- 引入增强 -->
        <property name="proxyTargetClass" value="true"/>                   <!-- 代理目标类(默认为 false,代理接口) -->
</bean>

We need a custom interceptor.

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;

import x.y.IHello;

@SuppressWarnings("serial")
public class CeremonyIntroAdvice extends DelegatingIntroductionInterceptor implements IHello {

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        return super.invoke(mi);
    }

    @Override
    public void sayHello() {
        System.out.println("Say hello.");
    }

}

In Spring, the introduction of enhancements to achieve, need to inherit from DelegatingIntroductionInterceptor.

See DelegatingIntroductionInterceptor invoke the following class () method of the source.

@Override
    public Object invoke(MethodInvocation mi) throws Throwable {
            // 检测是否是引入增强
        if (isMethodOnIntroducedInterface(mi)) {
            // 执行实现了引入增强接口的delegate对象的增强方法
            Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments());

            // Massage return value if possible: if the delegate returned itself,
            // we really want to return the proxy.
            if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) {
                Object proxy = ((ProxyMethodInvocation) mi).getProxy();
                if (mi.getMethod().getReturnType().isInstance(proxy)) {
                    retVal = proxy;
                }
            }
            return retVal;
        }

        return doProceed(mi);
    }

Internal AopUtils.invokeJoinpointUsingReflection () method, in fact, reflected method call.

try {
    ReflectionUtils.makeAccessible(method);
    return method.invoke(target, args);
}

Finally, write a test method to test.

public static void main(String[] args) {

    FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
            "D:/workspace/Spring4.2.5/bin/applicationContext.xml");

    CeremonyService service = context.getBean("ceremonyProxy", CeremonyService.class);
    service.sayBye();

    IHello hello = (IHello) service;
    hello.sayHello();

    context.close();
}

Output:

Say bye.
Say hello.

to sum up

High-quality video programming shangyepingtai.xin

Article describes how to use more, but less describes the principle of the article, I prefer to introduce the principle of the article. I hope this post useful to you.

Published 122 original articles · won praise 47 · views 30000 +

Guess you like

Origin blog.csdn.net/fengzongfu/article/details/105323962