1. 程式人生 > >spring aop 的代理工廠

spring aop 的代理工廠

參考 https://docs.spring.io/spring/docs/4.3.11.RELEASE/spring-framework-reference/htmlsingle/#aop-understanding-aop-proxies

package org.springframework.aop.framework

public class ProxyFactory extends ProxyCreatorSupport {
...
}

 

public class ProxyCreatorSupport extends AdvisedSupport {

    
private AopProxyFactory aopProxyFactory; ... /** * Create a new ProxyCreatorSupport instance. */ public ProxyCreatorSupport() { this.aopProxyFactory = new DefaultAopProxyFactory(); } ... }

 

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 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 required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } ... }

 

boolean java.lang.reflect.Proxy.isProxyClass(Class<?> cl)


Returns true if and only if the specified class was dynamically generated to be a proxy class using the getProxyClass method or the newProxyInstance method. 

The reliability of this method is important for the ability to use it to make security decisions, so its implementation should not just test if the class in question extends Proxy.

Parameters:
cl the class to test
Returns:
true if the class is a proxy class and false otherwise
Throws:
NullPointerException - if cl is null

 

JDK 示例

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

public class Main {
    public static void main(String[] args) {

        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new SomeAdvice());
        Pojo pojo = (Pojo) factory.getProxy();

        // this is a method call on the proxy!
        pojo.foo();
    }
}

class SimplePojo implements Pojo {

    @Override
    public void foo() {
        // this next method invocation is a direct call on the 'this' reference
        this.bar();
    }

    @Override
    public void bar() {
        // some logic...
        System.out.println("barrrrrrrr");
    }

}

interface Pojo {
    public void foo();

    public void bar();
}

class SomeAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String name = invocation.getMethod().getName();
        System.out.println(name + " start");
        Object proceed = invocation.proceed();
        System.out.println(name + " end");
        return proceed;
    }

}

執行結果:

foo start
barrrrrrrr
foo end

通過代理才會執行advise , 自呼叫(self-invocation 例如 this.bar())不會執行代理的advise 。

解決方式有兩種,其一:

暴露代理(不推薦使用)

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.framework.ProxyFactory;

public class Main {
    public static void main(String[] args) {

        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new SomeAdvice());
        factory.setExposeProxy(true);
        Pojo pojo = (Pojo) factory.getProxy();

        // this is a method call on the proxy!
        pojo.foo();
    }
}

class SimplePojo implements Pojo {

    @Override
    public void foo() {
        // this works, but... gah!
        ((Pojo) AopContext.currentProxy()).bar();
    }

    @Override
    public void bar() {
        // some logic...
        System.out.println("barrrrrrrr");
    }

}

interface Pojo {
    public void foo();

    public void bar();
}

class SomeAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String name = invocation.getMethod().getName();
        System.out.println(name + " start");
        Object proceed = invocation.proceed();
        System.out.println(name + " end");
        return proceed;
    }

}

執行結果:

foo start
bar start
barrrrrrrr
bar end
foo end

其二:

抽新類,避免自呼叫

 

CGLIB 示例

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

public class Main {
    public static void main(String[] args) {

        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addAdvice(new SomeAdvice());
        SimplePojo pojo = (SimplePojo) factory.getProxy();

        // this is a method call on the proxy!
        pojo.foo();
    }
}

class SimplePojo {

    public void foo() {
        this.bar();
    }

    public void bar() {
        // some logic...
        System.out.println("barrrrrrrr");
    }

}


class SomeAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String name = invocation.getMethod().getName();
        System.out.println(name + " start");
        Object proceed = invocation.proceed();
        System.out.println(name + " end");
        return proceed;
    }

}

執行結果:

foo start
barrrrrrrr
foo end

暴露代理同JDK 動態代理

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.framework.ProxyFactory;

public class Main {
    public static void main(String[] args) {

        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addAdvice(new SomeAdvice());
        factory.setExposeProxy(true);
        SimplePojo pojo = (SimplePojo) factory.getProxy();

        // this is a method call on the proxy!
        pojo.foo();
    }
}

class SimplePojo {

    public void foo() {
        ((SimplePojo) AopContext.currentProxy()).bar();
    }

    public void bar() {
        // some logic...
        System.out.println("barrrrrrrr");
    }

}


class SomeAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String name = invocation.getMethod().getName();
        System.out.println(name + " start");
        Object proceed = invocation.proceed();
        System.out.println(name + " end");
        return proceed;
    }

}

執行結果:

foo start
bar start
barrrrrrrr
bar end
foo end

 

相關內容

@Transactional 為什麼會失效

https://docs.spring.io/spring/docs/4.3.11.RELEASE/spring-framework-reference/htmlsingle/#transaction-declarative-annotations

Method visibility and @Transactional

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

 

import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;import org.springframework.aop.framework.ProxyFactory;
public class Main {public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());factory.addInterface(Pojo.class);factory.addAdvice(new SomeAdvice());factory.setExposeProxy(true);Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!pojo.foo();}}
class SimplePojo implements Pojo {
@Overridepublic void foo() {// this next method invocation is a direct call on the 'this' referencethis.bar();}
@Overridepublic void bar() {// some logic...System.out.println("barrrrrrrr");}
}
interface Pojo {public void foo();
public void bar();}
class SomeAdvice implements MethodInterceptor {
@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {String name = invocation.getMethod().getName();System.out.println(name + " start");Object proceed = invocation.proceed();System.out.println(name + " end");return proceed;}
}