sping揭秘12SpringAOP的实现机制

Posted cutter_point

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sping揭秘12SpringAOP的实现机制相关的知识,希望对你有一定的参考价值。

 

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();
    }
}

结果展示:

 

 

以上是关于sping揭秘12SpringAOP的实现机制的主要内容,如果未能解决你的问题,请参考以下文章

sping揭秘8容器内部事件发布

Sping AOP Capabilities and Goals

sping揭秘3Spring容器中bean默认是保持一个实例

sping揭秘4某些无法注册到IOC容器的对象如何交给spring托管

sping揭秘17@Around,@Introduction

sping揭秘20spring的orm