SpringBoot学习记录 二

一个有趣的案例(约定编程)

一个简单的业务(拼图1)

public interface HelloService {
    void sayHello(String name);
}
public class HelloServiceImpl implements HelloService {

    @Override
    public void sayHello(String name) {
        if(name == null || name.trim().equals("")){
            throw new RuntimeException("name is null");
        }
        System.out.println("hello," + name);
    }
}

一个简单的拦截器(拼图2)

public interface Interceptor {

    //事前方法
    boolean before();

    //事后方法
    void after();

    /**
     * 取代原有事件方法
     * @param invocation 回调参数,可以通过它的proceed方法,回调原有事件
     * @return 原有事件返回对象
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    Object around(Invocation invocation) throws InvocationTargetException, IllegalAccessException;

    //是否返回方法。事件没有发生异常执行
    void afterReturning();

    //事后异常方法,当事件发生异常后执行
    void afterThrowing();

    //是否使用around方法取代原有方法
    boolean userAround();
}
public class MyInterceptor implements Interceptor {
    @Override
    public boolean before() {
        System.out.println("before......");
        return true;
    }

    @Override
    public void after() {
        System.out.println("after......");
    }

    @Override
    public Object around(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
        System.out.println("around before......");
        Object obj = invocation.proceed();
        System.out.println("around after......");
        return obj;
    }

    @Override
    public void afterReturning() {
        System.out.println("afterReturning......");
    }

    @Override
    public void afterThrowing() {
        System.out.println("afterThrowing......");
    }

    @Override
    public boolean userAround() {
        return true;
    }
}

around中Invocation

public class Invocation {

    private Object[] params;
    private Method method;
    private Object target;

    public Invocation(Object[] params, Method method, Object target) {
        this.params = params;
        this.method = method;
        this.target = target;
    }

    public Object proceed() throws InvocationTargetException, IllegalAccessException{
        return method.invoke(target, params);
    }

    public Object[] getParams() {
        return params;
    }

    public void setParams(Object[] params) {
        this.params = params;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }
}

制定约定(绘画拼图模板)

当使用代理类获取到代理对象,然后强转为被代理类相应接口类型并调用相应方法时

  1. 先执行Interceptor中的before方法
  2. 如果Interceptor中的useAround方法返回true(这里默认为true),则执行around方法,由于Invocation回调参数的存在,会调用被代理类的目标方法;如果useAround方法返回false,则直接调用被代理类的目标方法
  3. 无论怎样,after方法都会执行
  4. 若发生异常,则调用afterThrowing方法;若无,则调用afterReturning方法
  • 附上图在这里插入图片描述

  • 预测一下执行结果
    before…
    around before…
    hello,tom
    around after…
    after…
    afterReturning…
    ------------name is null-------------
    before…
    around before…
    after…
    afterThrowing…

将约定内容织入到约定流程中(将拼图块按一定规则填入拼图模板)

public class ProxyBean implements InvocationHandler{
    private Object target = null;
    private Interceptor interceptor = null;

    /**
     * 绑定代理对象
     * @param target 被代理对象
     * @param interceptor 拦截器
     * @return 代理对象
     */
    public static Object getProxyBean(Object target, Interceptor interceptor){
        ProxyBean proxyBean=new ProxyBean();
        proxyBean.target=target;
        proxyBean.interceptor=interceptor;

        Object proxy =
                Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), proxyBean);
        return proxy;
    }

    /**
     * 处理代理对象方法逻辑
     * @param proxy 代理对象
     * @param method 当前方法
     * @param args 运行参数
     * @return 方法调用结果
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        boolean exceptionFlag=false;
        Invocation invocation=new Invocation(args, method, target);
        Object retObj=null;

        try {
            if(this.interceptor.before()){
                retObj=this.interceptor.around(invocation);
            }else{
                retObj=method.invoke(target, args);
            }
        } catch (Exception e) {
            exceptionFlag=true;
        }

        this.interceptor.after();

        if(exceptionFlag){
            this.interceptor.afterThrowing();
        }else{
            this.interceptor.afterReturning();
            return retObj;
        }

        return null;
    }

    public static void main(String[] args) {
        HelloService proxyBean =
                (HelloService) ProxyBean.getProxyBean(new HelloServiceImpl(), new MyInterceptor());
        proxyBean.sayHello("tom");

        System.out.println("------------name is null-------------");

        proxyBean.sayHello(null);
    }
}

执行代码验证

在这里插入图片描述在这个例子中,JDK动态代理是关键,但我仍未弄明白动态代理内部的执行流程,如代理类对象执行相应方法时,怎么走的InvocationHandler中的invoke方法,其源码有点难懂

参考书籍
《深入浅出Spring Boot 2.x》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值