zoukankan      html  css  js  c++  java
  • 谈谈什么是AOP以及动态代理技术

    摘要

    本文讲解了aop的基本概念,并且简要的介绍了其实现原理。

    AOPのwhy以及what

    我们都知道,软件的良好组织应该是分模块的,而且这种模块最好是垂直结构的。OOP思想正好契合这种设计模式。但是在我们的实际软件组织中,有些功能总是会破坏这种结构,设想下面的场景,在程序设计中,我们最常用的功能便是日志功能了,我们无法把这些日志代码集中管理起来,他总是会散布在我们的代码中,将我们的代码污染。又或者我们需要在现有业务逻辑上加入一些特定的功能,这些功能也许或许每个模块都需要,比如说我们需要监测每个模块的性能,又或者为每个模块添加一些安全检查逻辑,但是又不能为使用该模块的使用者带来麻烦,也就是说我们想用非侵入式编程的方法实现此功能。在面向对象中,我们只能采用继承式的方法来添加这些逻辑。但是这样最明显的问题及时,代码组织会迅速膨胀。加入说我们原先有100个具体的类,我们想为每个类添加打印日志功能,这样我们就需要继承这100个类,重写每一个需要打印日志的方法。久而久之,我们的软件一定会变得难以管理。AOP就是为了解决这个问题而提出的。它采用了动态代理的思想,实现了上述的功能。

    动态代理

    为方便讲述动态代理,用下面的具体例子来帮助理解,假设我们软件模块中有这样的一个类SomeTask,我们现在想为这个类添加一些额外的功能。比如我现在想进行一些安全检查的代码。我们应该怎么办?(我,还能怎么办,打开SomeTask的代码,进入到具体方法,改就完事了。AOP:滚!)下面用伪代码进行描述:

    interface Task{
        public void execute(args:Object[]);
    }
    Class SomeTask implements Task {
        public void execute(args:Object[]) {
            
        }
    }
    interface SecurityCheck{
        public boolean securityCheck();
    }
    class SecurityCheckImpl implements SecurityChcek{
        public boolean securityCheck(){
            
        }
    }
    

    假如我们不允许对SomeTask的源代码进行改动,我们能想到最直接的方法便是面向白盒编程,也及时继承Task,然后进行方法的重写。代码如下:

    class TaskWithSecurityCheck implements Task{
        private Task task;
        private SecurityCheck sc;
        public TaskWithSecurityCheck(Task t,SecurityCheck s){
            task = t;
            sc = s;
        }
        @Override
        public void execute(args:Object[]) {
            boolean success = sc.securityCheck();
            if(success) task.execute();
            else {
                System.out.prrintln("securiy check fail forbbiden execute the task");
            }
        }
    }
    

    嗯,这样的代码也还可以,当我们的软件规模不大时,但是设想一下,假如我们需要为每个模块假如这样的安全检查呢,头铁的可以继续刚,我还是去寻找更好的解决方案了。这个时候,实际上需要我们的动态代理出场了,哦,对了,上面的模式叫做静态代理模式。

    动态代理可以实现将欲添加的功能完全抽象出来,那个模块想要添加这个功能,动态的添加就好了,非常的方便。话不多说,我们直接看代码:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class SecurityCheckProxy implements InvocationHandler {
    	private Object target;
        private SecurityChcke sc;
    	public CalTaskTimeProxy(Object t,SecurityCheck sc) {
    		this.target = t;
            this.sc = sc;
    	}
    	@SuppressWarnings("unchecked")
    	public  <T> T create() {
    		return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    	}
    	@Override
    	public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
    		//before();
    		Object result = null;
                   boolean success = sc.securityCheck();
    		try {
                        if(success) result = method.invoke(target,args);
                        return result;
    		} catch (IllegalAccessException e) {
    		}
                    finally{
                        if(result == null) {
                        System.out.println("task forbbiden execute cause security check fail");
                 }
             }
    	}
    }
    

    我们的客户端调用代码如下:

    public void main(String[] args) {
        Task task = new SecurityCheckProxy(new SomeTask();
            			new SecurityCheckImpl()).create();
        task.execute();
    }
    

    可以看出,在客户端的使用除了多了需要配置的代理以外,没有任何的异常,这样我们就实现了对于原先代码不进行任何改动的前提下,从而添加了我们想要的新功能。实际上这也是AOP实现的基本思想。同时也是java反射的一个经典应用。

  • 相关阅读:
    error: with modifiers "public "
    移除元素
    删除有序数组中的重复项
    最长公共前缀
    如何杀死window进程
    IDEA卡顿问题
    合并两个有序链表
    开闭原则
    字符集和sql语句GROUPBY查询的版本问题
    里氏替换原则
  • 原文地址:https://www.cnblogs.com/zhangshoulei/p/13280793.html
Copyright © 2011-2022 走看看