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 AOP Capabilities and Goals
sping揭秘3Spring容器中bean默认是保持一个实例
sping揭秘4某些无法注册到IOC容器的对象如何交给spring托管