【SSH系列】静态代理&&动态代理

从设计模式说起

代理模式是二十三中设计模式中的一种,代理模式就是指由一个代理主题来操作真实的主题,真实的主题执行具体的业务操作,而代理主题负责其她相关业务,简而言之,代理模式可以由以下三个部分组成:

a、抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
b、代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
c、真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
第一次接触代理模式的是在学习大话设计模式的时候,首先,小编带着小伙伴们一起回顾一下代理模式:
概念:
为其他对象提供一种代理以控制对这个对象的访问,代理是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理。
uml图

  生活中的代理

当客户端需要调用某个对象时,客户端实际上也不关心是否准确得到该对象,她只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理。                                                                                                                                  看到此处,相信读者应该对Spring的AOP框架有点感觉了:当Spring容器中的被代理Bean实现了一个或多个接口时,Spring所创建的AOP代理就是这种动态代理。Spring AOP与此示例应用的区别在哪里呢?Spring AOP更灵活,当Sping定义InvocationHandler类的invoke()时,它并没有以硬编码方式决定调用哪些拦截器,而是通过配置文件来决定在invoke()方法中要调用哪些拦截器,这就实现了更彻底的解耦——当程序需要为目标对象扩展新功能时,根本无须改变Java代理,只需要在配置文件中增加更多的拦截器配置即可。

 代理的分类

a、静态代理

由程序员创建或工具生成代理类的源码,再编译代理类,所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

b、 动态代理

动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。 
接着,小编分别讲解一下静态代理&&动态代理,加上相关的demo,希望可以帮助到有需要的小伙伴。
        静态代理
       具体用户管理实现类

package com.bjpowernode.spring;

public class UserManagerImpl implements UserManager {

	public void addUser(String username, String password) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.add()--------");
	}

	public void delUser(int userId) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.delUser()--------");
	}

	public String findUserById(int userId) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.findUserById()--------");
		return "张三";
	}

	public void modifyUser(int userId, String username, String password) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.modifyUser()--------");
	}

//	private void checkSecurity() {
//		System.out.println("-------checkSecurity-------");
//	}
}

代理类--代理用户管理实现类

package com.bjpowernode.spring;

public class UserManagerImplProxy implements UserManager {

	private UserManager userManager;

	public UserManagerImplProxy(UserManager userManager) {
		this.userManager = userManager;
	}

	public void addUser(String username, String password) {
		checkSecurity();
		userManager.addUser(username, password);
	}

	public void delUser(int userId) {
		checkSecurity();
		userManager.delUser(userId);
	}

	public String findUserById(int userId) {
		checkSecurity();
		return userManager.findUserById(userId);
	}

	public void modifyUser(int userId, String username, String password) {
		checkSecurity();
		userManager.modifyUser(userId, username, password);
	}

	private void checkSecurity() {
		System.out.println("-------checkSecurity-------");
	}
}

客户端调用

package com.bjpowernode.spring;

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SecurityHandler hander = new SecurityHandler();
		UserManager useraManager = (UserManager)hander.createProxyInstance(new UserManagerImpl());
		useraManager.addUser("张三", "123");

	}

}

ok,结合代码部分,具体说说静态代理,代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合),对于如上的客户端代码,newUserManagerImpl()可以应用工厂将它隐藏。接着继续讲解动态代理。

动态代理

通过上面的demo,一个代理只能代理一个类型,而且是在编译器就已经确定被代理的对象。而动态代理实在运行的时候,通过反射机制来实现动态代理,并且能够代理各种类型的对象。在java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持,接着我们来编写具体的代码部分。
具体实现类,代码如下所示:

package com.bjpowernode.spring;

public class UserManagerImpl implements UserManager {

	public void addUser(String username, String password) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.add()--------");
	}

	public void delUser(int userId) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.delUser()--------");
	}

	public String findUserById(int userId) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.findUserById()--------");
		return "张三";
	}

	public void modifyUser(int userId, String username, String password) {
		//checkSecurity();
		System.out.println("---------UserManagerImpl.modifyUser()--------");
	}

}

动态创建代理对象的类

根据如上的介绍,你会发现每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类
所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理

在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象

在Java中要想实现动态代理机制,需要//动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类  

public class LogHandler implements InvocationHandler {  

    // 目标对象
    private Object targetObject;
    //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
    public Object newProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
        //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
        //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
        //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
        //根据传入的目标返回一个代理对象
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),this);
    }
    @Override
    //关联的这个实现类的方法被调用时将被执行
    /*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("start-->>");
        for(int i=0;i<args.length;i++){
            System.out.println(args[i]);
        }
        Object ret=null;
        try{
            /*原对象方法调用前处理日志信息*/
            System.out.println("satrt-->>");  

            //调用目标方法
            ret=method.invoke(targetObject, args);
            /*原对象方法调用后处理日志信息*/
            System.out.println("success-->>");
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("error-->>");
            throw e;
        }
        return ret;
    }  

}

客户端代码如下所示:

public class Client {  

    public static void main(String[] args){
        LogHandler logHandler=new LogHandler();
        UserManager userManager=(UserManager)logHandler.newProxyInstance(new UserManagerImpl());
        //UserManager userManager=new UserManagerImpl();
        userManager.addUser("1111", "张三");
    }
}  

ok,动态代理的代码就展示到这里,讲解一下动态创建代理对象的类,被代理对象targetObject通过参数传递进来,我们通过targetObject.getClass().getClassLoader()获取ClassLoader对象,然后通过targetObject.getClass().getInterfaces()获取它实现的所有接口,然后将targetObject包装到实现了InvocationHandler接口的LogHandler对象中。通过newProxyInstance函数我们就获得了一个动态代理对象。

区别和联系

静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类,静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行的社会化才知道。

动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。 
    还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。

小编寄语:该博文,小编主要简单的介绍了静态代理和动态代理,从设计模式中的代理模式开始说起,到静态代理和动态代理,静态代理是实实在在存在的,是我们自己用键盘打出来的,在编译期加入,提前就指定好了who来调用who,效率高;动态代理,一个类让事情变得更加简单,可以解决创建多个静态代理的麻烦,避免冗余的代码,无论是静态代理还是动态代理,都各有千秋,在项目中该如何使用,小伙伴可以自己掂量,SSH系列,未完待续......

时间: 2024-10-01 06:42:36

【SSH系列】静态代理&&动态代理的相关文章

spring 代理(静态代理&amp;动态代理&amp;cglib代理)

介绍spring AOP之前 先介绍三种常见的代理方式:静态代理,动态代理,cglib代理 代理概述: 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式:即通过代理访问目标对象.这样好处: 可以在目标对象实现的基础上,增强额外的功能操作.(扩展目标对象的功能). 举例:明星(邓紫棋)<------经纪人<-------用户 目标        (代理) 一.静态代理 1)代理的对象要实现与目标对象一样的接口 2)举例:保存用户(模拟) Dao,直接保存 DaoProxy,给保存

代理模式(静态代理+动态代理)——JAVA

代理模式是常用的java设计模式,他的特征是代理类与目标类有同样的接口,代理类主要负责为目标类预处理消息.过滤消息.把消息转发给目标类,以及事后处理消息等.代理类与目标类之间通常会存在关联关系,一个代理类的对象与一个目标类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用目标类的对象的相关方法,来提供特定的服务. 结构图如下: 按照代理的创建时期,代理类可以分为静态代理和动态代理. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类(Proxy)的.clas

啰里吧嗦式讲解java静态代理动态代理模式

一.为啥写这个 文章写的比较啰嗦,有些东西可以不看,因为想看懂框架, 想了解SSH或者SSM框架的设计原理和设计思路, 又去重新看了一遍反射和注解, 然后看别人的博客说想要看懂框架得先看懂设计模式,于是遇到了动态代理这个大坑, 写博客等于是对自己学习过程的一个回顾和总结 本文主要参考欧阳锋的10分钟看懂动态代理设计模式 二.理解和弄懂代理的前期准备 2.1.什么是代理 简单来说就是有活不自己干,让别人干, 比如你不想写作业, 让同学帮你写,然后写上自己的名字, 这个同学就是你的代理, 帮你处理一

静态代理$动态代理

什么是静态代理? 静态代理就是代理模式,给真实类做了个增强的方法 比如你有个房源,你还有代理人那么这个代理人就会给你的怎是房源的基础上,夸大点让你的房源增加人脉... 就要用到增强方法,就在代理类中给你的方法增强 //静态代理模式public class Progects {/* @Test public void dd() {//真实代理 Subject jk=new Real(); //代理对象 Proxy hj=new Proxy(); //调度代理对象(jk)方法增强 hj.setSub

Java代理/静态代理/动态代理/代理模式

代理模式:即Proxy Pattern,常用的设计模式之一.代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问. 代理概念 :为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代.代理类负责请求的预处理.过滤.将请求分派给委托类处理.以及委托类执行完请求后的后续处理. 下面以明星为例模拟需求说明静态代理和动态代理. 一.首先看静态代理 看下图:歌迷希望明星许巍唱歌(许巍即是目标对象),但不可能直接找

java 反射之静态and动态代理

首先说一下我们什么情况下使用代理? (1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强. (2)我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 .那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻

设计模式-代理/动态代理

最近一段时间在看spring的源码,发现里面大量的使用的代理.代理:就是用代理类实现委托类的一些功能和附加的预处理功能(包括消息过滤,日志等).代理(proxy)模式:指目标对象给定代理对象,并由代理对象代替真实对象控制客户端对真 实对象的访问, java的代理分为静态代理和动态代理,java 对动态代理有很好的支持,提供了 InvocationHandler接口和 Proxy 类. 1.动态代理和静态代理的区别 静态代理,代理类要实现被代理接口的所有的方法.  动态代理是利用java反射机制,

Spring框架_代理模式(静态代理,动态代理,cglib代理)

共性问题: 1. 服务器启动报错,什么原因? * jar包缺少.jar包冲突 1) 先检查项目中是否缺少jar包引用 2) 服务器: 检查jar包有没有发布到服务器下:                                      用户库jar包,需要手动发布到tomcat. (每次新建项目) 3) 重新发布项目 * 配置文件错误 (web.xml / struts.xml /bean.xml /hibernate.xml / *.hbm.xml) 明确的提示 * 端口占用 * we

静态代理与动态代理的简单使用

代理模式(Proxy Pattern)是一种比较常见的设计模式,在很多场合都会被用到. 所谓代理指的是让其他的类代替完成一些任务(执行一些方法等),在软件开发中代理模式具有非常重要的作用,面向切面编程(AOP)便是基于代理模式运作的编程范式. 下面介绍一下其中的静态代理与动态代理,基于Java语言. 静态代理: 首先由一个HelloWorld接口,其中有一个方法,print public interface HelloWorld { void print(); } 接下来是实现了HelloWor