JDK动态代理和责任链模式

 

JDK动态代理在添加前、后置处理时存在的缺陷?

一  在JDK动态代理模式中代理类通过实现InvocationHandler接口,在invoke方法可以调用目标类的方法,并在调用目标方法时实现前、后置处理。jdk动态代理是基于接口实现,角色分为接口、目标类、代理类

1 接口:

public interface IUser {
    void say();
}

2 目标类:

public class UserImpl implements  IUser {
    @Override
    public void say() {
        System.out.println("hello world");
    }
}

3 代理类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestProxy implements InvocationHandler {

    private Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置通知");
        Object obj = method.invoke(target, args);
        System.out.println("后置通知");
        return obj;
    }
    public Object createProxy(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    public static void main(String[] args){
        TestProxy testPro = new TestProxy();
        IUser userImpl = (IUser) testPro.createProxy(new UserImpl());
        userImpl.say();
    }
}

4 运行结果:

前置通知
hello world
后置通知

二 通过上述代码发现,对于前、后置代码在invoke方法中,不符合面向对象编程思想,不利于降低代码耦合度。前后置处理操作类似拦截器Interceptor,拦截的目标类方法可以封装为对象Invocation,在拦截器的interceptor()方法执行的时候可以调用Invocation对象的process()方法执行目标方法,因此可以对于上述代码可以重构为下述结构:

1 拦截的目标方法封装的实体类

import lombok.Data;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@Data
public class Invocation {
    public Method method;

    public Object target;

    public Object[] args;

    public Invocation(Object proxy, Method method, Object[] args) {
        this.target = proxy;
        this.method = method;
        this.args = args;
    }
    //执行目标方法
    public Object process(){
        Object obj=null;
        try {
            obj =  method.invoke(target, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return obj;
    }
}

2 代理类实现:

import lombok.Data;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

@Data
public class MyProxy implements InvocationHandler {

    private Interceptor interceptor;

    private Object target;

    public MyProxy(Interceptor interceptor, Object target) {
        this.interceptor = interceptor;
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Invocation invocation = new Invocation(target, method, args);
        return interceptor.interceptor(invocation);
    }
}

 

3 拦截接口Interceptor

public interface Interceptor {
    //拦截方法
    Object interceptor(Invocation invocation);
    //创建代理对象
    Object plugin(Object obj);
}

4拦截接口实现:

mport java.lang.reflect.Proxy;

public class ServiceInterceptor implements  Interceptor{
    @Override
    public Object interceptor(Invocation invocation) {
        System.out.println("业务处理前置通知");
        Object obj = invocation.process();
        System.out.println("业务处理后置通知");
        return obj;
    }

    public  Object plugin(Object target){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new MyProxy(this, target));
    }
}

5 拦截接口实现类


import lombok.Data;
import java.lang.reflect.Proxy;

@Data
public class LoginInterceptor implements  Interceptor {

    @Override
    public Object interceptor(Invocation invocation) {
        System.out.println("请先输入账号密码...");
        Object obj =  invocation.process();
        System.out.println("登录成功...");
        return obj;
    }

    public  Object plugin(Object target){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new MyProxy(this, target));
    }

    public static void main(String[] args){
        LoginInterceptor loginInterceptor = new LoginInterceptor();
        IUser iUser = new UserImpl();
        iUser = (IUser) loginInterceptor.plugin(iUser);
        ServiceInterceptor serviceInterceptor = new ServiceInterceptor();
        iUser = (IUser) serviceInterceptor.plugin(iUser);
        iUser.say();
    }
}

6 运行结果:


业务处理前置通知
请先输入账号密码...
hello world
登录成功...
业务处理后置通知

三  通过上述发现,当存在多个拦截器时代码结构不够简洁,因此可以使用拦截器链,优化后代码结构如下:

1 创建拦截器链实体类,通过list集合保存拦截器:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestInterceptorChain {

    Object target;

    public TestInterceptorChain(Object target) {
        this.target = target;
    }

    List list = new ArrayList();

    public void addInterceptor(Interceptor interceptor){
        list.add(interceptor);
    }

    public Object pluginAll(){
        for(int i = 0; i < list.size(); i++){
           target = list.get(i).plugin(target);
        }
        return  target;
    }

    public List getInterceptor(){
        return Collections.unmodifiableList(list);
    }

    public static void main(String[] args) {
        IUser obj = new UserImpl();
        TestInterceptorChain testInterceptorChain = new TestInterceptorChain(obj);
        testInterceptorChain.addInterceptor(new LoginInterceptor());
        testInterceptorChain.addInterceptor(new ServiceInterceptor());
        obj = (IUser) testInterceptorChain.pluginAll();
        obj.say();
    }
}

2 运行结果:

业务处理前置通知
请先输入账号密码...
hello world
登录成功...
业务处理后置通知

 

你可能感兴趣的:(mybatis)