`
felly822
  • 浏览: 9701 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

在AOP基础之上的一个钩子程序实现

阅读更多

  先解释下钩子程序,英文为HOOK。

   Hook解释

  Hook是Windows中提供的一种用以替换DOS下“中断”的系统机制,中文译为“挂钩”或“钩子”。在对特定的系统事件进行hook后,一旦发生已hook事件,对该事件进行hook的程序就会受到系统的通知,这时程序就能在第一时间对该事件做出响应。

  另一解释:

  钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

  钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

 


钩子程序有利有弊,弊端在于其安全性无法控制,利端是因为它的灵活,适应客户多变的需求, 但是我们并不用修改现有的程序源代码。

 

      好,下面我们开始来实现这个HOOK程序,对这个HOOK还不是很理解没关系,只要看完本文,即可完全了解HOOK,淡然HOOK有很多实现模式,这里我仅仅使用注入模式实现,原则上只要稍加变通,即可实现替换模式,修复,破解等等模式。

     处于对程序的安全考虑,HOOK的控制点都在一个切面上,所以系统利用AOP对业务逻辑的各个部分进行隔离。

 

 

先来看看我一个切面的实现,说白了也就是一个代理,java的代理很多人都做过,我贴出我的全部代理类代码。

挂钩程序都通过一个数据结构表配置起来,然后在每次执行一个业务方法的时候 都必须先判断是否有挂钩程序,有的话,执行挂钩程序逻辑,否则直接执行主业务方法。

     

package com.aiyc.framework;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.aiyc.framework.conn.DbUtils;
import com.aiyc.framework.conn.TransactionManager;
import com.aiyc.framework.hander.Manager;
import com.aiyc.framework.icommon.IManager;

/**
 * @author felly
 * @version $Revision: 1.0 $, $Date: Feb 28, 2011 3:45:08 PM $
 */
public class InvokeDrator implements java.lang.reflect.InvocationHandler {
	private Object proty;
	private IManager im = null;//管理钩子程序
   //绑定代理对象
	public Object bind(Object obj) {
		this.proty = obj;
		try {
			im = Manager.getManager(null);//将挂钩配置全部读取到内存
		} catch (Exception e) {
			e.printStackTrace();
		}
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
				.getClass().getInterfaces(), this);
	}

	/*
	 * 方法代理
	 * 
	 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
	 *      java.lang.reflect.Method, java.lang.Object[])
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		Object result = null;
		TransactionManager tx = DbUtils.getTranManager();//事务控制
		try {

			tx.beginTransaction();
			invokeBefore(proty, args, result);// /之前挂钩
			result = protySkipmain(method, args);//主函数
			invokeAfter(proty, args, result);// 之后挂钩

		} catch (Exception e) {//异常控制
			e.printStackTrace();
			tx.rollbackAndClose();
			throw new Exception("事务处理失败,请重新确认!,详细错误信息:" + e);
		}

		tx.commitAndClose();

		return result;
	}

	private Object protySkipmain(Method method, Object[] args) throws Exception {
		if (!im.isSkipMain(proty.getClass().getName()))//是否跳过主函数的执行判断
			return method.invoke(proty, args); // 业务方法
		return null;
	}

	public void invokeBefore(Object proxy, Object[] args, Object result) {// 执行servic方法之前
		try {
			if (im.hasHander(proxy.getClass().getName())) {
				im.invoke(proxy, args, IManager.BEFORE, result);
			}
		} catch (Exception e) {
                                //出现异常不要处理,放置主方法不能被执行
		}
	}
  
	public void invokeAfter(Object proxy, Object[] args, Object result) {// 执行servic方法之后
		try {
			if (im.hasHander(proxy.getClass().getName())) {
				im.invoke(proxy, args, IManager.AFTER, result);
			}
		} catch (Exception e) {
             //
		}

	}
}
 

 

    然后来看  IManager 的实现

 

   public interface IManager {

	public static final String BEFORE = "01";
	public static final String AFTER = "02";
	public static final String OPEN_HANDER = "01";
	public static final String CLOSE_HANDER = "02";
	public static final String INPUT = "input";
	public static final String OUTPUT = "input";
	public static final String SKIP_MAIN = "02";
	public static final String NOSKIP_MAIN = "01";
	public  static final String _method_name = "handerMethod";
	public  static final String _method_service = "handerService";
	public  static final String _hander_type = "handerType";
	public  static final String _hander_vaild = "handerVaild";// 必须执行的hander
	public  static final String _method_input = "handerInput";
	public  static final String _method_output = "handerReturn";
	public  static final String _method_condition = "handerCondition";
	public  static final String _method_url = "handerUrl";
	public  static final String _method_hander_skipmain = "handerSkipmain";
	public void invoke(Object proxy, Object[] args, String handerType,
			Object result) throws Exception;// 获取挂钩程序,格式为

	// 函数对象,函数入参数\,处理

	public boolean hasHander(String handerName) throws Exception;
	
	public boolean isSkipMain(String handerName ) throws Exception;

}
 

  接下来是一个调用业务方法的类,每个业务方法都必须通过这个类来调用。这样就能实现业务方法都只有一个入口。

接下去我最后后贴出一个实际的使用例子。便于理解整个程序的控制过程。

 public abstract class ServiceFactory {

public  static Object getClassInstance(String clzName) throws ClassNotFoundException {

Object obj = null;

try {

Class cls = Class.forName(clzName);

obj = (Object) cls.newInstance();

} catch (ClassNotFoundException cnfe) {

throw new UserException(cnfe.getMessage());

} catch (Exception e) {

throw new UserException(e.getMessage());

}

return obj;

}

 

public static Object getAOPProxyedObject(String clzName) throws Exception {

return getAOPProxyedObject(getClassInstance(clzName + "Invoke")

.getClass());

}

 

 

 

public static Object getAOPProxyedObject(Class f) throws Exception {

Object proxy = null;

InvokeDrator handler = new InvokeDrator();

Object obj = getClassInstance(getLodObjectPath(f.getName()));

if (obj instanceof ServiceInvoke) {

if (obj != null) {

proxy = handler.bind(obj);

} else {

throw new UserException("错误,创建对象不存在!,错误对象" + f.getName());

// throw

}

} else {

throw new UserException("错误, 对象必须实现接口ServiceInvoke,错误对象:!"

+ f.getName());

 

}

return proxy;

}

 

private static final String FINAL_SEVICE = "service";

 

private static String getLodObjectPath(String path) throws Exception {

if (StringUtils.isNullOrBank(path)) {

throw new UserException("错误, 对象路径错误,错误对象:!" + path);

}

return path.replaceAll("invoke", FINAL_SEVICE).replaceAll("Invoke", "");

 

}

}


 

 

接下来是一个正在IManager的实现,Manaer 是一个抽象工厂类,获取HanderManager 之用。该类实现了全部的挂钩程序逻辑

 

    public class HanderManager extends Manager {

 

	private String handerType(String type) {
		if (IManager.BEFORE.equals(type))
			return "之前";
		else
			return "之后";
	}
      //执行HOOK方法
	public void invoke(Object proxy, Object[] args, String handerType,
			Object result) throws Exception {
		String handerName = proxy.getClass().getName();
		List data = searchHanders(handerName, handerType);
		Iterator it = data.iterator();
		while (it.hasNext()) {
			Map map = (Map) it.next();
			String method = (String) map.get(_method_service);
			String hander = (String) map.get(_method_name);
			String input = (String) map.get(_method_input);
			String output = (String) map.get(_method_output);
			String condition = (String) map.get(_method_condition);
			String url = (String) map.get(_method_url);
			List arg = new ArrayList();
			// /////////////////hander和主程序相同的话跳过
			if (!StringUtils.isNullOrBank(method) && method.equals(hander)) {
				continue;
			}
			// ///////////////先决条件是否满足。
			if (!StringUtils.isNullOrBank(condition)
					&& !analyzePriorCond(args, result, condition)) {
				continue;
			}
			// /////////////////////////////////////
			int ite = handleInput(arg, input, args);
			String classz = this.getMethosName(method);
			String methodz = this.getMehodn(method);
			Object obj = ComponentProxy.invoke(url, classz, methodz, arg
					.toArray());
			int ret = handleOutput(result, obj, output);// 出参处理

		}

	}

	/**
	 * 解析先决条件,先决条件是一个逻辑表达式
	 */
	private boolean analyzePriorCond(Object[] orgnParams, Object orgnResult,
			String priorCond) throws Exception {
		if (priorCond == null || priorCond.equals(""))
			return true; // 无先决条件
		BoolExprsCalc calc = new BoolExprsCalc(priorCond);
		List<String> varNames = calc.getVarNames();
		Map<String, Object> varMap = new HashMap<String, Object>();
		for (int i = 0; i < varNames.size(); i++) {
			String varName = varNames.get(i); // varName格式:input0、output0
			Object value = null;
			boolean isArrOrgnResult = (orgnResult instanceof Object[]); // 主函数输出参数是否为数组
			if (varName.indexOf(INPUT) == 0) {
				value = getValue(varName, orgnParams, true, -1, 5);
			} else if (varName.indexOf(OUTPUT) == 0) {
				value = getValue(varName, orgnResult, isArrOrgnResult, -1, 6);
			}
			varMap.put(varName, value);
		}
		calc.setVarValues(varMap);
		return calc.calc();
	}

	// //获取值
	private Object getValue(String expression, Object obj, boolean isArray,
			int pointIndex, int prefixLen) throws Exception {
		Object value = null;
		int k = -1;
		if (pointIndex > -1) {
			if (isArray) {
				k = Integer.parseInt(expression
						.substring(prefixLen, pointIndex));
				value = PropertyUtils.getProperty(((Object[]) obj)[k],
						expression.substring(pointIndex + 1));
			} else {
				value = PropertyUtils.getProperty(obj, expression
						.substring(pointIndex + 1));
			}
		} else {
			if (isArray) {
				k = Integer.parseInt(expression.substring(prefixLen));
				value = ((Object[]) obj)[k];
			} else {
				value = obj;
			}
		}
		return value;
	}
//获取bean值
	private Object setValue(String expression, Object obj, boolean isArray,
			int pointIndex, int prefixLen, Object value) throws Exception {
		int k = -1;
		if (pointIndex > -1) {
			if (isArray) {
				k = Integer.parseInt(expression
						.substring(prefixLen, pointIndex));
				PropertyUtils.setProperty(((Object[]) obj)[k], expression
						.substring(pointIndex + 1), value);
			} else {
				PropertyUtils.setProperty(obj, expression
						.substring(pointIndex + 1), value);
			}
		} else {
			if (isArray) {
				k = Integer.parseInt(expression.substring(prefixLen));
				((Object[]) obj)[k] = value;
			} else {
				obj = value;
			}
		}
		return obj;
	}
//入参处理
	private int handleInput(List args, String input, Object srcArgs[])
			throws Exception {
		// 解析input
		if (StringUtils.isNullOrBank(input)) {
			return 1;
		}
		String inputs[] = input.split(":");
		int len = Integer.parseInt(inputs[0]);
		if (len <= 0)
			return 2;
		String dets[] = inputs[1].split(",");
		if (dets.length != len)
			return 3;
		for (int i = 0; i < len; i++) {
			if (dets[i].indexOf(INPUT) != -1) {// 找原方法的入参
				int x = -1;

				if (dets[i].indexOf(".") == -1) {// 不找原方法的入参对象的某一个属性
					x = Integer.parseInt(dets[i].substring(INPUT.length()));
					if (x >= srcArgs.length)
						continue;
					args.add(srcArgs[x]);
				} else {// 找属性
					x = Integer.parseInt(dets[i].substring(INPUT.length(),
							dets[i].indexOf(".")));
					if (x >= srcArgs.length)
						continue;
					String pro = dets[i].substring(dets[i].indexOf(".") + 1);
					args.add(ComponentProxy.getMethodValue(srcArgs[x],
							getInputName(pro)));
				}
			} else {
				args.add(dets[i]);// 字符类型
			}
		}

		return 0;
	}

	private String getInputName(String method) {
		return "get" + method.substring(0, 1).toUpperCase()
				+ method.substring(1);
	}

	private String getOutputName(String method) {
		return "set" + method.substring(0, 1).toUpperCase()
				+ method.substring(1);
	}

	/**
	 * 出参处理
	 * 
	 * @param result
	 * @param ret
	 * @param output
	 * @return
	 * @throws Exception
	 */
	private int handleOutput(Object result, Object ret, String output)
			throws Exception {
		if (StringUtils.isNullOrBank(output)) {
			return 1;
		}
		// return->result.xx
		// return->result
		// return.xx->result
		// return.xx->result.xx
		// return.xx->result.xx,return.yy->result.yy .........
		if (output.indexOf("->") == -1)
			return 2;

		String rr[] = output.split(",");
		for (int i = 0; i < rr.length; i++) {
			String bl[] = rr[i].split("->");
			if (bl[0].indexOf(".") == -1) {// 整个赋值
				if (bl[1].indexOf(".") == -1) {
					result = ret;

				} else {
					String method = bl[1].substring(bl[1].indexOf(".") + 1);
					ComponentProxy.getMethodValue(result, this
							.getOutputName(method), new Object[] { ret });
				}
			} else {
				if (bl[1].indexOf(".") == -1) {
					String method = bl[0].substring(bl[1].indexOf(".") + 1);
					Object o = ComponentProxy.getMethodValue(ret, this
							.getInputName(method));
					result = o;
				} else {
					String method = bl[0].substring(bl[1].indexOf(".") + 1);
					String methodreturn = bl[1]
							.substring(bl[1].indexOf(".") + 1);
					Object o = ComponentProxy.getMethodValue(ret, this
							.getInputName(method));

					ComponentProxy.getMethodValue(result, this
							.getOutputName(methodreturn), new Object[] { o });
				}
			}
		}

		return 0;
	}
//获取HOOK,一个方法可能存在多个HOOK
	private List searchHanders(String handerName, String handerType)
			throws Exception {
		List handers = ContextHander.instance().getHanderData();
		List para = new ArrayList();
		Iterator it = handers.iterator();
		while (it.hasNext()) {
			Map map = (Map) it.next();
			String method = (String) map.get(_method_name);
			String handertype = (String) map.get(_hander_type);
			String vaild = (String) map.get(_hander_vaild);
			if (getMethosName(method).equals(handerName)
					&& handertype.equals(handerType)
					&& IManager.OPEN_HANDER.equals(vaild)) {
				para.add(map);
			}
		}

		return para;
	}
//获取方法名
	private String getMethosName(String path) {
		int index = path.lastIndexOf(".");
		return path.substring(0, index);
	}
          //获取入参配置
	private String getMehodn(String path) {
		int index = path.lastIndexOf(".");
		return path.substring(index + 1);
	}
//是否存在HOOK
	public boolean hasHander(String handerName) throws Exception {
		List handers = ContextHander.instance().getHanderData();
		if (handers == null)
			return false;
		Iterator it = handers.iterator();
		while (it.hasNext()) {
			Map map = (Map) it.next();
			String method = (String) map.get(_method_name);
			String vaild = (String) map.get(_hander_vaild);
			if (getMethosName(method).equals(handerName)
					&& IManager.OPEN_HANDER.equals(vaild)) {
				return true;
			}
		}
		return false;

	}

	public boolean isSkipMain(String handerName) throws Exception {

		List handers = ContextHander.instance().getHanderData();
		if (handers == null)
			return false;
		Iterator it = handers.iterator();
		while (it.hasNext()) {
			Map map = (Map) it.next();
			String skip = (String) map.get(_method_hander_skipmain);
			String method = (String) map.get(_method_name);

			if (getMethosName(method).equals(handerName)
					&& SKIP_MAIN.equals(skip)) {
				return true;
			}
		}
		return false;
	}

}
 

 

 好了。HOOK程序完成了。接下来看一个具体的使用.先看看Action的程序

 

	public ActionForward save(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		ResForm model = (ResForm) ((WapperObject) form).getWrapperObject();

		ResServiceInvoke invoke = (ResServiceInvoke) com.aiyc.framework.ServiceFactory
				.getAOPProxyedObject(ResServiceInvoke.class);

		// ///////////////////
		invoke.save(model);
		request.setAttribute("resList", invoke.queryRes(model));
		ActionMessages messages = new ActionMessages();
		WebGetMessage.getMessage(request, messages);
		saveMessages(request, messages);
		return mapping.findForward(INIGT_PAGE);
	}
 

       ResServiceInvoke 的代码; public interface ResServiceInvoke extends ServiceInvoke { public void save(ResForm model) throws Exception; public List queryRes(ResForm model) throws Exception; public int execute(ResForm model) throws Exception;// 执行更新 }

 

 

  //ResService 业务方法

 public class ResService extends BaseService implements ResServiceInvoke {

。。。。。。。。。。

 

 

      //挂钩测试程序

     public String executeAfter(ResForm model) throws Exception {

System.out.println(this.getClass().getClassLoader().getResource("")

+ "测试成功" + this.getClass().getName());

 

return "ok";

}

      //保存方法

     public void save(ResForm model) throws Exception {

// TODO Auto-generated method stub

String msg = "";

if (!StringUtils.isNullOrBank(model.getSpId())) {

String type = model.getSaveType();

if (Constant.DELETE.equals(type)) {

dao.delete(model);

msg = "删除成功!";

} else if (Constant.MODUFY.equals(type)) {

dao.modify(model);

msg = "修改成功!";

} else {

throw new UserException("错误,错误的操作类型! ");

}

} else {

dao.save(model);

msg = "保存成功!";

}

 

sendMsg(msg);

}

     。。。。。。。。。。。。。。。。。

 

保存方法执行后,配置挂钩方法为executeAfter程序。

 

那么在执行完成保存后,挂钩方法同时也会被执行,并且是通过配置实现,你可以完全独立开一个模块来写HOOK程序,然后注入到业务方法中执行。

 

 

 

 

 

 

1
2
分享到:
评论

相关推荐

    实现AOP的一个例子

    1. **切面(Aspect)**:切面是AOP的核心,它封装了一组相关功能,这些功能会在程序的不同位置被插入执行。切面由两部分组成:**通知(Advice)**和**切点(Pointcut)**。 2. **通知(Advice)**:通知是在特定...

    一个简单的spring AOP的实现

    3. 连接点(Join Point):连接点是在程序执行过程中能够插入切面的一个特定点,比如方法调用、字段访问等。 4. 切入点(Pointcut):切入点是匹配连接点的规则,定义了通知将在哪些连接点应用。可以使用表达式或者...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    在Java开发中,反射机制是实现动态代理的关键技术之一。反射提供了在运行时访问和操作类的能力,这使得动态代理的实现成为可能。在Java中,可以使用java.lang.reflect包下的相关类和接口实现动态代理。 例如,通过...

    AOP基础与配置说明

    面向切面编程(AOP,Aspect Oriented Programming)是Spring框架中的一个重要特性,它提供了一种模块化程序设计的方法,可以将关注点分离到不同的切面中,从而提高代码的可复用性和可维护性。在Spring框架中,AOP...

    spring 的AOP 基础

    在Java开发中,Spring框架以其强大的功能和灵活性被广泛使用,而Spring AOP(面向切面编程)是其重要组成部分之一。AOP允许开发者将关注点从核心业务逻辑中分离出来,比如日志记录、权限检查等,通过切面来实现这些...

    基于注解实现SpringAop

    基于注解实现SpringAop基于注解实现SpringAop基于注解实现SpringAop

    Spring AOP基础关于AOP是什么的理解

    6. 目标(Target):如果一个对象在程序执行过程中受到某个 AOP 的修改,那么它就叫做一个目标对象。 AOP 的种类有两种: 1. 静态 AOP:静态 AOP 最早的 AOP 类型,通常都是静态的。即在编译过程中,静态 AOP 通过...

    AOP下的权限控制实现

    在AOP中,权限控制可以通过定义切入点(pointcut)来实现,即在特定方法执行前后插入权限检查的逻辑,而无需在每个涉及权限的方法内部重复编写代码。 在J2EE应用程序开发中,AOP的拦截能力尤为关键。通过拦截器,...

    Unity结合三导实现依赖注入跟AOP

    在软件开发中,Unity是一个流行的依赖注入容器,它主要用于.NET应用程序,尤其是对于Unity游戏引擎的开发者来说,这个框架可以帮助他们更好地管理和组织代码。另一方面,面向切面编程(AOP)是一种设计模式,允许...

    Xml配置实现AOP

    - **CGLIB代理**:如果目标对象没有实现任何接口,Spring会使用CGLIB库生成一个目标对象的子类,并在子类的方法上插入切面逻辑。CGLIB代理不依赖于接口,因此适用于任何类。 在XML配置中,我们需要定义`&lt;aop:config...

    Spring AOP实现机制

    Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的可复用性和可维护性。 ### 1. ...

    Spring Aop的简单实现

    在这个基于配置文件的实现中,我们首先需要在Spring配置文件(如applicationContext.xml)中定义一个切面。切面通常由一个或多个通知组成,我们可以使用`&lt;aop:config&gt;`标签来声明切面。例如: ```xml &lt;aop:config&gt; ...

    AOP使用CGLIB实现AOP功能

    Spring AOP实现方法之一:CGLIB 实现AOP功能

    AOP的实现机制.

    3. 通知(Advice):在特定连接点上执行的代码,例如,一个环绕通知(Around advice)会在方法调用前后执行。 4. 切入点(Pointcut):定义一组连接点的模式,用于指定通知将应用在哪里。 5. 引入(Introduction)...

    注解方式实现AOP编程

    `@Aspect`是定义一个切面的注解,通常会定义在一个独立的类上。这个类将包含切点(Pointcut)和通知(Advice)。 切点是程序执行过程中的特定点,如某个方法的调用。在Spring中,我们可以使用`@Pointcut`注解来定义...

    .net平台AOP的实现

    在.NET平台上实现AOP,我们可以借助于不同的库和技术,如PostSharp、Unity、Autofac等。下面我们将深入探讨.NET平台AOP的实现方法和应用。 首先,我们需要理解AOP的基本概念。AOP的核心是切面(Aspect),它封装了...

    利用C#实现AOP常见的几种方法详解

    面向切面编程(AOP,Aspect Oriented Programming)是一种编程范式,旨在通过将关注点分离,使得系统设计更加模块化。AOP的核心思想是将应用程序的横切关注点(如日志、事务管理、安全检查等)从核心业务逻辑中解耦...

    模拟spring aop【一】基于jdk动态代理实现的aop

    在Java中,动态代理机制允许我们在运行时创建一个实现了特定接口的新类。这个新类的实例可以代理目标对象,执行额外的操作,如方法调用前后的增强。Spring AOP利用这一特性来实现切面的织入,即在目标方法执行前、后...

    Asp.net Core 3.1基于AspectCore实现AOP实现事务、缓存拦截器功能

    在net core2.2时,我当时就尝试过用autofac实现aop,但这次我不想用autofac,我用了一个更轻量级的框架,AspectCore。 用起来非常非常的简单,但一开始还是走了一点弯路,主要是网上都是net core3以下的教程,3以下...

    Spring AOP的简单实现

    Spring AOP(面向切面编程)是Spring框架中的一个重要组件,它允许我们在不修改源代码的情况下,对程序的行为进行统一管理和增强。在这个场景中,我们将使用Spring AOP来实现一个日志记录的功能,以追踪系统中各个...

Global site tag (gtag.js) - Google Analytics