• 【sping揭秘】12、SpringAOP的实现机制


    SpringAOP的实现机制

    设计模式代理模式

    参考我之前的代理模式

    http://www.cnblogs.com/cutter-point/p/5226642.html

    这里写个简单的案例

    package spring.aop.designPattern;
    
    /**
     * 
     * Title: ISubject.java
     * Description:代理模式的资源接口类 
     * @author xiaof
     * @date 2018年4月7日
     * @version 1.0 
     *
     */
    public interface ISubject {
        
        public void request();
    }
    package spring.aop.designPattern;
    
    /**
     * 
     * Title: SubjectImpl.java
     * Description: 被访问者,或者被访问的资源实现类
     * @author xiaof
     * @date 2018年4月7日
     * @version 1.0 
     *
     */
    public class SubjectImpl implements ISubject {
    
        @Override
        public void request() {
            // TODO Auto-generated method stub
            System.out.println("this is subjectImpl cutter_point ! ");
        }
    
    }
    package spring.aop.designPattern;
    
    /**
     * 
     * Title: SubjectProxy.java
     * Description: 代理实现类
     * @author xiaof
     * @date 2018年4月7日
     * @version 1.0 
     *
     */
    public class SubjectProxy implements ISubject {
    
        
        private ISubject subject;
        
        @Override
        public void request() {
            System.out.println("pre operation subjectproxy");
            if(subject != null) 
                subject.request();
            
            System.out.println("after operation subjectproxy");
        }
    
        public ISubject getSubject() {
            return subject;
        }
    
        public void setSubject(ISubject subject) {
            this.subject = subject;
        }
    
        
    }
    package spring.aop.designPattern;
    
    import org.junit.Test;
    
    public class Main {
    
        @Test
        public void test1() {
            SubjectImpl si = new SubjectImpl();
            SubjectProxy sp = new SubjectProxy();
            sp.setSubject(si);
            
            sp.request();
        }
    }

    测试一波:

     

    这就是,比如我们要对subjectimpl进行代理的时候,我们就需要根据ISubject接口实现一个代理类对象

    好,基于此点,

    缺点1:如果我们一个类不存在接口类型,并且是第三方的类对象,比如我们现在有一个subjectimpl2,这个类没有实现ISubject接口,那么我们的subjectimpl还能进行代理吗?显然是不能的

    缺点2:我们发现对一个subjectimpl对象进行代理就要实现一个代理类subjectProxy,那如果我们项目用有一个万类对象需要进行代理,那么我们需要创建一万个proxy类,好吧,我反正会疯的。。。

    动态代理

    这个jdk的动态代理主要是,proxy类和invocationhandler接口

    package spring.aop.designPattern;
    
    /**
     * 
     * Title: ISubject.java
     * Description:代理模式的资源接口类 
     * @author xiaof
     * @date 2018年4月7日
     * @version 1.0 
     *
     */
    public interface ISubject {
        
        public void request();
    }
    package spring.aop.designPattern;
    
    /**
     * 
     * Title: SubjectImpl.java
     * Description: 被访问者,或者被访问的资源实现类
     * @author xiaof
     * @date 2018年4月7日
     * @version 1.0 
     *
     */
    public class SubjectImpl implements ISubject {
    
        @Override
        public void request() {
            // TODO Auto-generated method stub
            System.out.println("this is subjectImpl cutter_point ! ");
        }
    
    }

    代理类

    package spring.aop.dynamicPorxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.util.Date;
    
    import spring.aop.util.DateUtil;
    
    /**
     * 
     * Title: RequestCtrlInvocationHandler.java
     * Description: jdk动态代理对象
     * @author xiaof
     * @date 2018年4月7日
     * @version 1.0 
     *
     */
    public class RequestCtrlInvocationHandler implements InvocationHandler {
        
        /**
         * 代理对象
         */
        private Object target;
        /**
         * 00:00:00
         */
        private String beginTime;
        /**
         * 00:00:00
         */
        private String endTime;
        
    
        public RequestCtrlInvocationHandler(Object target, String beginTime, String endTime) {
            this.target = target;
            this.beginTime = beginTime;
            this.endTime = endTime;
        }
    
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //判断是否是request方法,如果是进行拦截操作
            if(method.getName().equals("request")) {
                //判断当前时间是否在区间内,如果是,那么就进行相应的操作
                if(DateUtil.isInDate(new Date(), beginTime, endTime)) {
                    System.out.println("区间内时间,拦截成功");
                    return method.invoke(target, args);
                } else {
                    System.err.println("区间外时间");
                    return null;
                }
            }
            return method.invoke(target, args);
        }
    
    }

    最后测试:

    目前时间!

     

    那么我们修改时间区间,看是否会产生不一样的后果!!!

    0-12点

     

     

    那么我们把时间改为22点呢

    拦截成功

    不多BB,这个还是有问题,无法处理接口类问题

    动态字节码生成

    使用cblib

    package spring.aop.cglib;
    
    import java.lang.reflect.Method;
    import java.util.Date;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import spring.aop.util.DateUtil;
    
    /**
     * 
     * Title: RequestCtrlCallback.java
     * Description: 动态字节码技术
     * @author xiaof
     * @date 2018年4月7日
     * @version 1.0 
     *
     */
    public class RequestCtrlCallback implements MethodInterceptor {
        
        private static final Log logger = LogFactory.getLog(RequestCtrlCallback.class);
    
        /**
         * 00:00:00
         */
        private String beginTime;
        /**
         * 00:00:00
         */
        private String endTime;
        
        
        
        public RequestCtrlCallback(String beginTime, String endTime) {
            this.beginTime = beginTime;
            this.endTime = endTime;
        }
    
    
    
        @Override
        public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
    
            //如果是我们需要拦截的方法,那么进行相应的操作
            if(arg1.getName().equals("request")) {
                if(DateUtil.isInDate(new Date(), beginTime, endTime)) {
                    //在对应的时间区间内,成功
                    logger.info("成功拦截到对应的区间,放行!");
                    return arg3.invokeSuper(arg0, arg2);
                } else {
                    logger.error("错误时间区间!!");
                    return null;
                }
            }
            
            return arg3.invokeSuper(arg0, arg2);
            
        }
    
    
    
        public String getBeginTime() {
            return beginTime;
        }
    
    
    
        public void setBeginTime(String beginTime) {
            this.beginTime = beginTime;
        }
    
    
    
        public String getEndTime() {
            return endTime;
        }
    
    
    
        public void setEndTime(String endTime) {
            this.endTime = endTime;
        }
    
    }
    package spring.aop.cglib;
    
    import org.junit.Test;
    import org.springframework.cglib.proxy.Enhancer;
    
    import spring.aop.designPattern.SubjectImpl;
    
    public class Main {
    
        @Test
        public void test1() {
            //使用cglib代理对象
            String beginTime = "00:00:00";
            String endTime = "20:00:00";
            Enhancer enhancer = new Enhancer();
            //设置代理类对象
            enhancer.setSuperclass(SubjectImpl.class);
            
            enhancer.setCallback(new RequestCtrlCallback(beginTime, endTime));
            
            //生成代理对象
            SubjectImpl proxyObj = (SubjectImpl) enhancer.create();
            
            proxyObj.request();
        }
    }

    结果展示:

  • 相关阅读:
    vs编译出现 fatal error LNK1281:无法生成 SAFESEH 映像
    $apply()和$digest()——angular
    JS获取URL中参数值
    NeDB——node嵌入式数据库
    VS Code常用插件
    js断点调试
    VS Code 使用Git进行版本控制
    VS Code快捷键
    用户tokenId
    node-webkit-updater——NW.js自动更新
  • 原文地址:https://www.cnblogs.com/cutter-point/p/8955139.html
Copyright © 2020-2023  润新知