java 动态代理—— Mybaties 拦截器链基本原理实现
1.摘要
Mybaties 中有个分页插件,之前有特意的去了解了一下原理 :https://www.cnblogs.com/jonrain0625/p/11168247.html,从了解中得知分页插件是基于Mybaties的拦截器去实现的,这个插件就是一个拦截器,和别的拦截器组成了Mybaties的拦截器链,然后所有的拦截器都对Executor 这个类 做了动态代理。本次主要的再次去学习下这个动态代理,去实现一个最基本的拦截器链的效果。当然还有spring aop 等很多地方都是基于动态代理去实现的,关于Aop可以在 :https://www.cnblogs.com/lcngu/p/5339555.html 去了解。本次也是基于这篇文章,及代码去学习和实现 拦截器链。
2.java动态代理
java中代理模式分静态代理和动态代理,而动态代理的实现有两种实现方法,一种是基于JDK 用 接口方法去实现 ,一种是基于CGLIB 基于类去实现 ,了解可以看:https://www.cnblogs.com/rinack/p/7742682.html 。
2.1 JDK 代理的基本使用:
1.创建代理类的接口
2.实现代理类执行的接口 InvocationHandler
3.生成代理对象:Proxy.newProxyInstance(loader, interfaces, h);
4.使用代理对象
3.示列
示列实现对user类的log方法拦截 ,在执行log方法之前,拦截器链中 LogIntercept1 和LogIntercept2 对log 方法拦截 ,做业务逻辑,拦截器链优点的很好体现是,实现耦合,可以高度的做到对内修改 。
3.1 新建代理类接口 和代理类
public interface Log {
public void log();
}
public class User implements Log{
String name = "user1";
public void log() {
System.out.println("user1 ----- 登陆");
}
}
3.2 新建 InvocationHandler 的实现类
为了封装 , 在bin方法中调用 Proxy.newProxyInstance 创建代理对象 ,把代理对象 和拦截器注入到代理对象,在 invoke方法中用拦截器代理执行。
public class Handler implements InvocationHandler{
//调用对象
private Object proxy;
//目标对象
private Intercept intercept; private Handler(Intercept target,Object proxy) {
this.intercept=target;
this.proxy=proxy;
}
public static Object bind(Intercept target,Object proxy){
return Proxy.newProxyInstance(
proxy.getClass().getClassLoader()
, proxy.getClass().getInterfaces(), new Handler(target,proxy));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return intercept.intercept(this.proxy,method,args);
}
}
3.3 创建拦截器
拦截器和拦截器的实现,偷懒写在一个文件中
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public interface Intercept {
Object intercept(Object o, Method m, Object[] os );
}
class LogIntercept1 implements Intercept { @Override
public Object intercept(Object o, Method m, Object[] os) {
try {
System.out.println("LogIntercept1 拦截登陆操作 做相关业务逻辑");
return m.invoke(o,os);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
} }
class LogIntercept2 implements Intercept { @Override
public Object intercept(Object o, Method m, Object[] os) {
try {
System.out.println("LogIntercept2 拦截登陆操作,做相关业务逻辑");
return m.invoke(o,os);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
}
3.4 创建一个代理工厂
在类中根据拦截器的数量,对代理类做循环。每次代理都把拦截器传入代理对象中 。
package 设计模式.com.pox.logPoxy; import java.util.ArrayList;
import java.util.List; public class ProxyFactory { List<Intercept> InterceptChain = new ArrayList<Intercept>() {
private static final long serialVersionUID = 1L; {
add(new LogIntercept1());
add(new LogIntercept2());
}
}; public Object proxy(Class<?> classz) throws Exception {
try {
Object obj = classz.newInstance();
return InterceptAll(obj);
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("代理异常");//抛出个异常,不另外设计异常类了,用RuntimeException 代替
}
} /** 拦截器代理
* @param obj
* @return
*/
private Object InterceptAll(Object obj) {
if(InterceptChain.isEmpty()) {
return obj;
}
for (Intercept intercept : InterceptChain) {
obj = Handler.bind(intercept,obj);
}
return obj;
} // 一下是单列的创建模式
public ProxyFactory(){
if(inner.proxyFactory != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
public static ProxyFactory getProxyFactory() {
return inner.proxyFactory;
}
private static class inner{
static ProxyFactory proxyFactory = new ProxyFactory();
}
}
3.5 测试
public class Test {
public static void main(String[] args) throws Exception {
ProxyFactory proxyFactory = ProxyFactory.getProxyFactory();
Log user = (Log) proxyFactory.proxy(User.class);
user.log();
}
}
/**
ouput :
LogIntercept2 拦截登陆操作
LogIntercept1 拦截登陆操作
user1 ----- 登陆
*/
以上就是一个简单的拦截器链实现,可以去查阅Mybaties的拦截器链,其原理是一样的,如果业务需要增加个拦截器链,实现接口 Intercept ,添加到代理工厂 ProxyFactory 拦截器链 InterceptChain中即可,实现高度的解耦功能。
java 动态代理—— Mybaties 拦截器链基本原理实现的更多相关文章
- 【转载】由浅入深分析mybatis通过动态代理实现拦截器(插件)的原理
转自:http://zhangbo-peipei-163-com.iteye.com/blog/2033832?utm_source=tuicool&utm_medium=referral 我 ...
- Mybatis使用动态代理实现拦截器功能
1.背景介绍 拦截器顾名思义为拦截某个功能的一个武器,在众多框架中均有“拦截器”.这个Plugin有什么用呢?或者说拦截器有什么用呢?可以想想拦截器是怎么实现的.Plugin用到了Java中很重要的一 ...
- 设计模式之jdk动态代理模式、责任链模式-java实现
设计模式之JDK动态代理模式.责任链模式 需求场景 当我们的代码中的类随着业务量的增大而不断增大仿佛没有尽头时,我们可以考虑使用动态代理设计模式,代理类的代码量被固定下来,不会随着业务量的增大而增大. ...
- Java动态代理——框架中的应用场景和基本原理
前言 之前已经用了5篇文章完整解释了java动态代理的原理,本文将会为这个系列补上最后一块拼图,展示java动态代理的使用方式和应用场景 主要分为以下4个部分 1.为什么要使用java动态代理 2.如 ...
- java动态代理基本原理及proxy源码分析一
本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的态度,于是对java动态代理的本质原理做了一些研究,于是便有了这个系列的文章 为了尽快进入正题,这里 ...
- java web 过滤器跟拦截器的区别和使用
注:文章整理自知乎大牛以及百度网友(电脑网络分类达人 吕明),特此感谢! 一.过滤器 1.什么是过滤器? 过滤器是一个程序,它先于与之相关的servlet或JSP页面运行在服务器上.过滤器可附加到一个 ...
- JAVA 动态代理原理和实现
在 Java 中动态代理和代理都很常见,几乎是所有主流框架都用到过的知识.在面试中也是经常被提到的话题,于是便总结了本文. Java动态代理的基本原理为:被代理对象需要实现某个接口(这是前提),代理对 ...
- Spring异步调用原理及SpringAop拦截器链原理
一.Spring异步调用底层原理 开启异步调用只需一个注解@EnableAsync @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTI ...
- Java动态代理全面分析
代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1 主题:规定代理类和真实对象共同对外暴露的接口: 2 代理类:专门代理真实对象的类: 3 ...
随机推荐
- crond 任务调度
crontab 进行定时任务的设置 任务调度:是指系统在某个时间执行的特定的命令或程序. 任务调度分类: 系统工作:有些重要的工作必须周而复始地执行.如病毒扫描等 个别用户工作:个别用户可能希望执行某 ...
- lua入门之环境搭建、第一个demo
前言 前段时间因为有些项目功能需要,自己研究了下lua,今天整理下,并以一个demo为示例演示 手机上的运行效果 分为几个步骤来逐步讲解. 1.lua介绍,为什么选择它? 2.环境安装 3.撸一个简单 ...
- Windows内核中的CPU架构-7-陷阱门(32-Bit Trap Gate)
Windows内核中的CPU架构-7-陷阱门(32-Bit Trap Gate) 陷阱门和中断门几乎是一模一样的: (注:图里高32位中的第11位的值为D,其实是1) 除了高32位中的type字段的内 ...
- 13.Fibonacci数
描述 无穷数列1,1,2,3,5,8,13,21,34,55...称为Fibonacci数列,它可以递归地定义为 F(n)=1 ...........(n=1或n=2) F(n)=F(n-1)+F(n ...
- WinForm训练一_改变窗体大小
1 //引用系统命名空间 2 using System; 3 //项目命名空间 4 using System.Collections.Generic; 5 using System.Component ...
- 躺平吧,平铺的窗口「GitHub 热点速览 v.21.47」
作者:HelloGitHub-小鱼干 用 macOS 系统经常会遇到的一个问题便是多开窗口如何快速找寻的问题,本周特推项目 yabai 便是来解决这个问题的.直接把所有窗口平铺,是不是很"正 ...
- 快速从零开始整合SSM,小白包会(1)
整合SSM,关键就是几个xml的配置. 准备: 1. Idea(配置好tomcat,可以安装插件freeMybatis,提高效率,安装插件不难,百度经验就有) 2. 下载好数据库MySql,以 ...
- [noi712]练级
先考虑一个联通块,可以发现这个联通快内不会存在两个偶数的点证明:如果存在,那么这两个点的某一条路径上的边全部反过来,可以使答案+2,即答案为点数或点数-1同时,发现答案的奇数点数一定与边数同奇偶,那么 ...
- [luogu5666]树的重心
考虑枚举一个点k,求其为重心的方案数暴力的做法是,将其作为根搜索,设最大子树大小为s1,次大为s2,对割掉的子树分类讨论:1.在子树中,分两种情况(都可以用线段树合并来做) (1)从s1中切掉一棵大小 ...
- 八、hive3.1.2 安装及其配置(本地模式和远程模式)
目录 前文 hive3.1.2 安装及其配置(本地模式和远程模式) 1.下载hive包 2.修改其环境变量 3.MySQL配置 Centos7 MySQL安装步骤: 1.设置MySQL源 2.安装My ...