VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • java进阶--动态代理核心知识及应用

 软件工程化发展到今天,前辈们总结的理论和原则不能光是试卷上的几个答案,毕业就还给老师,更重要的是应用于实践,刚入门的新手容易犯这些问题,一副不撞南墙不回头的气势,年轻有气概、有激情是好事,但是也不要妄自菲薄,单凭胆子大就蛮干、前辈们总结的经验一定要铭记在心,研发过程中,碰到类似的问题,多想想,不懂多问问,尽量避免采坑。

  重申设计模式六大原则:

  1、开闭原则

   一个软件实体,如类,模块和函数应该对外扩展开发,对内修改关闭。开闭原则的优点在于可以在不改动原有代码的前提下给程序扩展功能。大项目做到后面是个绕不开的问题哈,遵循这个原则也是给自己避开坑,哈哈。

  2、单一职责原则

   一个类只允许有一个职责,即只有一个导致该类变更的原因。如果一个类具有多种职责,就会有多种导致这个类变化的原因,从而导致这个类的维护变得困难。往往在软件开发中,随着需求的不断增加,可能会给原来的类添加一些本来不属于它的一些职责,从而违反了单一职责原则。如果我们发现当前类的职责不仅仅有一个,就应该将本来不属于该类真正的职责分离出去。不仅仅是类,函数也要遵循单一职责原则,即一个函数制作一件事情。如果发现一个函数里面有不同的任务,则需要将不同的任务以另一个函数的形式分离出去。如果类与方法的职责划分的很清晰,不但可以提高代码的可读性,更实际性地更降低了程序出错的风险,因为清晰的代码会让bug无处藏身,也有利于bug的追踪,也就是降低了程序的维护成本。

  3、依赖倒置原则

   依赖抽象而不是依赖实现。抽象不应该依赖细节,细节应该依赖抽象。高层模块不能依赖低层模块,二者都应该依赖抽象(面向接口编程的狂热份子,哈哈^_^)。针对接口编程,而不是针对实现编程。尽量不要从具体的类派生,而是以继承抽象类或实现接口来实现。关于高层模块与低层模块的划分可以按照决策能力的高低进行划分。业务层自然就处于上层模块,逻辑层和数据层自然就归类为底层。通过抽象来搭建框架,建立类和类的关联,以减少类间的耦合性。而且以抽象搭建的系统要比以具体实现搭建的系统更加稳定,扩展性更高,同时也便于维护。

  4、接口分离原则

   多个特定的客户端接口要好于一个通用性的总接口。即实际项目中应该避免过分抽象,遵循需求合理抽象。客户端不应该依赖它不需要实现的接口。不建立庞大臃肿的接口,接口中的方法应尽量少(尽量提取避免无关方法)。需要注意的是接口的力度也不能太小,如果过小,则会造成接口数量过多,使设计复杂化。避免同一个接口里面包含不同类职责的方法,接口责任划分更加明确,符合高内聚低耦合的思想。

  5、迪米特法则(最少知道原则)

   一个对象应该对尽可能少的对象有接触,也就是只接触那些真正需要接触的对象。一个类应该只和它的成员变量,方法的输入,返回参数中的类作交流,而不应该引入其他的类(间接交流)。实践迪米特法则可以良好地降低类与类之间的耦合,减少类与类之间的关联程度,让类与类之间的协作更加直接。

  6、里氏替换原则

   所有引用基类的地方必须能透明地使用其子类的对象,也就是说子类对象可以替换其父类对象,而程序执行效果不变。在继承体系中,子类中可以增加自己特有的方法,也可以实现父类的抽象方法,但是不能重写父类的非抽象方法,否则该继承关系就不是一个正确的继承关系。可以检验继承使用的正确性,约束继承在使用上的泛滥。

说的很精辟了!   

一、静态代理

   eg:

复制代码
package test.tmp;

interface interfDog {
    void info();
}

class OriginDog implements interfDog {

    @Override
    public void info() {
        System.out.println("this is originDog");
    }
    
}

//代理dog1
class StaticProxyDog1 implements interfDog{

    private OriginDog orDog = new OriginDog();
    
    @Override
    public void info() {
        System.out.println("StaticProxyDog1 doSomething before exec");
        orDog.info();
        System.out.println("StaticProxyDog1 doSomething after exec");
    }
    
}

//代理dog2
class StaticProxyDog2 implements interfDog{

    private OriginDog orDog = new OriginDog();
    
    @Override
    public void info() {
        System.out.println("StaticProxyDog2 doSomething before exec");
        orDog.info();
        System.out.println("StaticProxyDog2 doSomething after exec");
    }
    
}

public class StaticProxy {
    
    public static void main(String[] args) {
        StaticProxyDog1 p1 = new StaticProxyDog1();
        p1.info();
        System.out.println("===================================================");
        StaticProxyDog2 p2 = new StaticProxyDog2();
        p2.info();
    }
    
}
复制代码

 

二、静态代理和代理设计模式及应用

  (1)概念

   代理模式:对某一个目标对象提供它的代理对象,并且由代理对象控制对原对象的引用。

   静态代理:只能为给定接口的实现类做代理,如果接口不同则需要重新定义不同的代理类。(在代码运行前代理类的class编译文件就已经存在)

  (2)作用

  (2.1)权利代理功能:可屏蔽对原对象(主对象)的直接访问,代替原对象执行操作,实现原有对象与外部操作的隔离。

    例如:

      (2.1.1)权限身份验证(通过代理对象增加权限功能)。

      (2.1.2)RPC通过建立代理,直接实现了不存在的接口实现(消费者中只有接口,没有实现类)。

  (2.2)功能增强:代理对象可以在原有对象的基础上对原有功能进行扩展(增强)。例如:AOP中的切面操作是通过建立代理实现的。

三、装饰者模式

  (1)概念:

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

   (2)代码示例:

复制代码
package test.decor;

interface Dog {
    public void info();
}

class YelloDog implements Dog {
    @Override
    public void info() {
        System.out.println("this is yello dog");
    }
}

class WhiteDog implements Dog {
    @Override
    public void info() {
        System.out.println("this is White dog");
    }
}

abstract class DogDecorator implements Dog {
    protected Dog dog;

    protected DogDecorator(Dog dog) {
        this.dog = dog;
    }

    public void info() {
        dog.info();
    }
}

class DogDecoratorImpl extends DogDecorator {
    
    protected DogDecoratorImpl(Dog dog) {
        super(dog);
    }

    @Override
    public void info() {
        dog.info();
        System.out.println("this is dog decorate");
    }
}

public class DecoratorDemo {
    public static void main(String[] args) {
        DogDecorator yg = new DogDecoratorImpl(new YelloDog());
        yg.info();
        
        DogDecorator wg = new DogDecoratorImpl(new WhiteDog());
        wg.info();
    }
}
复制代码

 (4)引申:代理模式和装饰者模式区别

  网络上有些说法过于较真哈,简单理解,主要是代码用法上的区别(万变不离其宗,其实是原始概念上的区别),代理模式中代理对象可以对原有对象隐藏一些的具体信息(主要是代理执行)。使用代理模式的时候,一般在一个代理类中创建一个对象的实例(代理对象)。装饰者模式中将原始对象作为一个参数传给装饰者的构造方法。共同点是都可以对原有功能进行增强。

   其实设计模式主要的作用是看在项目中主要的应用场景,综合考虑项目的可扩展性、可维护性、以及尽量避免不必要的bug、工作量等因素,需要优化代码的逻辑实现,结合这些前辈们总结的设计模式,有相似的tip可以直接采用,或者结合项目需要进行优化组装。

 

四、动态代理

  这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。

(1)jdk动态代理

   (1.1)代码示例:

复制代码
package test.tmp;

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

interface InterfDog {
    void info();
}

class OriginDog implements InterfDog {
    @Override
    public void info() {
        System.out.println("this is Origin dog");
    }
}

public class DynamicProxyHandler implements InvocationHandler {

    private Object target;

    protected DynamicProxyHandler(Object target) {
        super();
        this.target = target;
    }

    protected DynamicProxyHandler() {
        super();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("bofore invoke");
        Object result = method.invoke(target, args);// 执行方法
        System.out.println("after invoke");
        return result;
    }

    public static void main(String[] args) {
        OriginDog yg = new OriginDog();
        DynamicProxyHandler proxyHandler = new DynamicProxyHandler(yg);
        // 基于接口动态生成实现类(生成代理对象)
        InterfDog proxyDog = (InterfDog) Proxy.newProxyInstance(InterfDog.class.getClassLoader(), new Class[] { InterfDog.class }, proxyHandler);
        proxyDog.info();
    }

}
复制代码

   (1.2)jdk动态代理实现原理

       调用Proxy.newProxyInstance生成代理类的实现类:

  • 调用getProxyClass0寻找或生成指定代理类(从缓存中取,如果没有,就生成一个放在缓存中 : 通过ProxyClassFactory生成);
  • 缓存调用ProxyClassFactory生成代理类,proxy class的生成最终调用ProxyClassFactory的apply方法;
  • ProxyGenerator.generateProxyClass使用生成的代理类的名称,接口,访问标志生成proxyClassFile字节码。
复制代码
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                throw new IllegalArgumentException(e.toString());
            }
复制代码

  生成字节码之后利用反射生成实例Proxy.newProxyInstance创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行时动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。

 


 

 

 (2)CGLib动态代理

   (2.1)代码示例:

复制代码
package test.tmp;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

class OriginDog {
    public void info(){
        System.out.println("this is origin dog");
    }
}

class MyMethodInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object sub, Method method, Object[] objs, MethodProxy methodProxy) throws Throwable {
        System.out.println("before invokeSuper");
        Object obj = methodProxy.invokeSuper(sub, objs);
        System.out.println("after invokeSuper");
        return obj;
    }
}

public class CGLibProxy {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OriginDog.class);
        enhancer.setCallback(new MyMethodInterceptor());
        OriginDog proxy = (OriginDog)enhancer.create();
        proxy.info();
    }
}
复制代码

   (2.1)CGLib动态代理原理

     //TODO 后续补充,一点点来嘛,精彩还在后面

五、AOP和动态代理及应用

   推荐一个帖子,对AOP理解很透彻,语言组织也好,诙谐幽默,感谢这些有价值的贡献者,地址 https://mp.weixin.qq.com/s/J-RQ2ltvo4d8hBuMrsvGGg

 

 查阅和参考了不少资料,感谢各路大佬分享,如需转载请注明出处,谢谢:https://www.cnblogs.com/huyangshu-fs/p/11454369.html


相关教程