動態代理實現AOP


代理

代理顧名思義:代為處理。不是對目標對象的直接操作,而是通過代理對目標對象進行包裝,此時可以在目標對象的基礎上添加額外的操作以滿足業務需求。圖示

分類:動態代理、靜態代理。

代理三要素:共同接口、真實對象、代理對象

引入代理的原因:

在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用【解耦】。 

靜態代理

public interface Action {
    public void doSomething();
}

public class Proxyc implements Action{
    Action realObject;
    public Proxyc(Action action) {
        realObject = action;
    }
    @Override
    public void doSomething() {
        System.out.println("被攔截前...");
        realObject.doSomething();
        System.out.println("被攔截后...");
    }

    public static void main(String[] args) {
        Proxyc proxy = new Proxyc(new RealObject());
        proxy.doSomething();
    }
}

優點:擴展原功能,不侵入代碼

缺點:假如有10個不同的實際對象,對應10個不同的方法,該如何寫呢?

1) 要么創建不同的代理類,代理后這樣:

proxy.doSomething()
proxy2.doSomething2()
proxy3.doSomething3()
...

問題:創建多個功能類似的代理類,僅傳入的真實對象不同

2) 要么創建一個代理,實現不同的接口:

proxy.doSomething()
proxy.doSomething2()
proxy.doSomething3()
...

問題:代理類不斷膨脹

動態代理

代理由靜態轉為靜態源於靜態代理引入的額外工作。

動態代理就是我們上面提到的方案一,只不過這些proxy的創建都是自動的並且是在運行期生成的。

很多繁瑣的編程可以用動態代理解決

實現方式

  • 反射(依賴接口)
    •   優點:最小化依賴關系;平滑jdk升級;代碼簡單
  • cglib等(依賴子類)
    •   優點:不限制實現接口;只操作關心的類;高性能

反射方式舉例

public interface Action {
    public void doSomething();
}

public class RealObject implements Action{
    @Override
    public void doSomething() {
        System.out.println("I'm RealObject~");
    }
}

public class DynamicProxyHandler implements InvocationHandler {
    private Object realObject;

    public DynamicProxyHandler(Object realObject) {
        this.realObject = realObject;
    }

    @Override
    public Object invoke(Object object, Method method, Object[] args) {
        Object result = null;
        try {
            result = method.invoke(realObject, args);
        } catch (InvocationTargetException|IllegalAccessException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) {
        RealObject realObject = new RealObject();
        Action action = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Action.class},
                new DynamicProxyHandler(realObject));
        action.doSomething();
    }
}

通過Proxy.newProxyInstance()生成代理對象,需要傳入3個參數:classLoader + 代理接口 + InvocationHandler實例,

其中InvocationHandler接口,該接口定義了一個invoke方法,proxy最是最終生成的一個代理實例,一般不會用到,參數method是被代理目標實例的某個具體的方法,通過它可以發起目標實例方法的反射調用;參數args是通過被代理實例某一個方法的入參,在方法反射調用時候使用,通過代理將橫切邏輯代碼和業務類的代碼編織到了一起。

動態代理的應用場景

日志

監控

鑒權

......

AOP

切面編程,是對OOP(面向對象編程)的一種補充,解決OOP其對對於跨越不同類、對象,糾纏邏輯變現的不足

AOP實例1

public interface Waiter {
    public void service();
}

public class ManWaiter implements Waiter{
    @Override
    public void service() {
        System.out.println("service...");
    }
}

 

public interface BeforeAdvice {
    public void before();
}

public interface AfterAdvice {
    public void after();
}

 

@Getter
@Setter
public class ProxyFactory {
    Object target;
    BeforeAdvice beforeAdvice;
    AfterAdvice afterAdvice;

    public Object createProxy() {
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class[] interfaces = target.getClass().getInterfaces();
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (beforeAdvice != null) {
                    beforeAdvice.before();
                }
                Object result = method.invoke(target, args);
                afterAdvice.after();
                return result;
            }
        };
        Object proxyObject = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxyObject;
    }

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new ManWaiter());
        proxyFactory.setBeforeAdvice(new BeforeAdvice() {
            @Override
            public void before() {
                System.out.println("Before Service.");
            }
        });
        proxyFactory.setAfterAdvice(new AfterAdvice() {
            @Override
            public void after() {
                System.out.println("After Service.........");
            }
        });
        Waiter waiter = (Waiter)proxyFactory.createProxy();
        waiter.service();
    }
}

 

AOP實例2

public interface UserService {
    public void service();
}

public class UserServiceImpl implements UserService{
    @Override
    public void service() {
        System.out.println("In Service.......");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Service end.");
    }
}

 

public class MethodPerformance {
    private long start;
    private long end;
    String serviceMethod;

    public MethodPerformance(String serviceMethod) {
        this.serviceMethod = serviceMethod;
        start = System.currentTimeMillis();
    }

    public void printPerformance() {
        end = System.currentTimeMillis();
        System.out.println(serviceMethod + " cost Time: " + (end - start));
    }
}

public class PerformanceMonitor {
    public static ThreadLocal<MethodPerformance> performanceThreadLocal = new ThreadLocal<>();

    public static void begin(String method) {
        System.out.println("Start monitor>>");
        MethodPerformance methodPerformance = new MethodPerformance(method);
        performanceThreadLocal.set(methodPerformance);
    }

    public static void end() {
        System.out.println("End monitor.");
        performanceThreadLocal.get().printPerformance();
    }
}

 

public class PerformanceHandler implements InvocationHandler {
    Object target;

    public PerformanceHandler(Object object) {
        target = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        Object result = null;
        try {
            PerformanceMonitor.begin(target.getClass().getName() + ":" + method.getName());
            result = method.invoke(target, args);
            PerformanceMonitor.end();
        } catch (IllegalAccessException| InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ClassLoader classLoader = userService.getClass().getClassLoader();
        Class[] interfaces = userService.getClass().getInterfaces();
        InvocationHandler invocationHandler = new PerformanceHandler(userService);
        UserService obj = (UserService) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        obj.service();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM