java中静态代理和动态代理
一、概述
代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。
按照代理的创建时期,代理类可以分为两种:
静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成。
我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制(反射),在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
二、图形描述
三、静态代理
静态代理的实现比较简单,代理类通过实现与目标对象相同的接口,并在类中维护一个代理对象。通过构造器塞入目标对象,赋值给代理对象,进而执行代理对象实现的接口方法,并实现前拦截,后拦截等所需的业务功能,一个典型的代理模式通常有三个角色,这里称之为**代理三要素**:共同的接口,代理对象、被代理对象
package com.bjsxt.staticProxy; /**
* Created by Administrator on 2019/3/10.
*/
public class TestStaticProxy { public static void main(String[] args){
//用法类似于线程的代理对象 new Thread(线程对象).start();
new WeddingCompany(new You()).happyMarry();
}
} /**
* 共同的接口
*/
interface Marry{
void happyMarry();
} /**
* 真实的角色,被代理角色
*/
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("你结婚了。。。");
}
} /**
* 代理角色,代理真实的角色
*/
class WeddingCompany implements Marry{ private Marry marry; //代理对象内部维护一个真实的角色(需要代理的角色) public WeddingCompany(Marry marry){
this.marry=marry;
} @Override
public void happyMarry() {
ready();
marry.happyMarry();
after();
} private void ready() {
System.out.println("布置婚礼。。。。");
}
private void after() {
System.out.println("闹洞房。。。。");
}
}
静态代理的总结
优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。
四、动态代理
在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象,动态代理有两种方式jdk动态代理和cglib动态代理
(1)使用jdk动态代理
我们看到jdk的代理机制必须要求被代理类实现某个方法,这样在生成代理类的时候才能知道重写那些方法。(事实上jdk动态代理会动态生成一个被代理类所实现的接口的实现类,跟静态代理类似)这样一个没有实现任何接口的类就无法通过jdk的代理机制进行代理,当然解决方法是使用cglib的代理机制进行代理。
package com.bjsxt.dynamicProxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map; /**
* JDK动态代理:使用前提(基于接口的实现)
* JDK动态代理:本质上生产了一个代理类,该代理与被代理目标实现相同的接口,
* 当前用户访 问代理类中的方法时,将委派InvacationHandler中的invoke()方法进行处理,
* 在invoke()方法中添加业务处理代理和回调被代理目标中方法。
*/
public class TestJdkProxy { public static void main(String[] args){
You you=new You();//创建被代理类
WeddingCompany weddingCompany=new WeddingCompany(you);
//生成代理类
Marry marry=(Marry)weddingCompany.createProxy();
//通过代理类,调用被代理类的方法
marry.happyMarry();
} } /**
* 共同的接口
*/
interface Marry{
void happyMarry();
} /**
* 真实的角色,被代理角色
*/
class You implements Marry {
@Override
public void happyMarry() {
System.out.println("你结婚了。。。");
}
} class WeddingCompany implements InvocationHandler { private Object target; //被代理的对象 public WeddingCompany(Object target){
this.target=target;
} /**
* 生成代理
* @return
*/
public Object createProxy(){
//获得加载被代理类的 类加载器
ClassLoader loader = target.getClass().getClassLoader();
//指明被代理对象实现的接口
Class<?>[] interfaces = target.getClass().getInterfaces();
//this是当前类的对象,也是代理类,之后想要调用被代理类的方法时,都会委托给这个类的
return Proxy.newProxyInstance(loader, interfaces, this);
} /**
*
* @param proxy 代理对象
* @param method 原对象被调用的方法
* @param args 方法传递的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ready();
Object returnValue=method.invoke(target,args);
after();
return returnValue;
} private void ready() {
System.out.println("布置婚礼。。。。");
}
private void after() {
System.out.println("闹洞房。。。。");
}
}
jdk动态代理总结
优点:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护目标对象和代理对象,只需在事件处理器中添加对方法的判断即可。
缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则无法使用JDK动态代理。
(2)使用cglib动态代理
cglib是通过继承的方式做的动态代理,因此,如果某个类被标记为final,那么它是无法使用cglib做动态代理。cglib会生成的代理类继承当前的被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等),因此被代理类有没有实现接口都是一样的
当然使用cglib需要添加下cglib所需的jar包:cglib-2.2.2.jar,asm-3.3.1.jar,asm-util-3.3.1.jar,ant-1.6.2.jar
package com.bjsxt.dynamicCglibProxy; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class TestCglibProxy { public static void main(String[] args){
You you=new You();//创建被代理类
WeddingCompany weddingCompany=new WeddingCompany(you);
//生成代理类
You you1=(You)weddingCompany.createProxy();
//通过代理类,调用被代理类的方法
you1.happyMarry();
} } /**
* 真实的角色,被代理角色
*/
class You { public void happyMarry() {
System.out.println("你结婚了。。。");
}
} /**
* 动态没生成代理对象
* 实现 MethodInterceptor方法代理接口,创建代理类
* 当访问代理中的方法时,委派给MethodInteceptor中的处理程序(intercept方法)进行出来,
* 在处理程序中添加了业务逻辑和回掉了被代理目标中的方法。
*/
class WeddingCompany implements MethodInterceptor { private Object target; //被代理的对象 public WeddingCompany(Object target){
this.target=target;
} /**
* 创建代理对象
* @return
*/
public Object createProxy() {
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
} /**
*
* @param proxy 生成的代理对象
* @param method 被调用的方法
* @param args 方法的入参
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
ready();
Object value = method.invoke(target, args);//回掉被代理对象中的方法
after();
return value;
} private void ready() {
System.out.println("布置婚礼。。。。");
}
private void after() {
System.out.println("闹洞房。。。。");
}
}
java中静态代理和动态代理的更多相关文章
- Java 静态代理和动态代理例子
代理Proxy: Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委 ...
- java静态代理和动态代理(一)
代理Proxy: Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题. 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为 ...
- JAVA学习篇--静态代理VS动态代理
本篇博客的由来,之前我们学习大话设计,就了解了代理模式,但为什么还要说呢? 原因: 1,通过DRP这个项目,了解到了动态代理,认识到我们之前一直使用的都是静态代理,那么动态代理又有什么好处呢?它们二者 ...
- java中静态代理,动态代理知识的补充
文章转载自:http://blog.csdn.net/jialinqiang/article/details/8950989 一.Java动态代理 相对于静态代理的代理类在编译时生成(.class文件 ...
- JAVA中的代理技术(静态代理和动态代理)
最近看书,有两个地方提到了动态代理,一是在Head First中的代理模式,二是Spring AOP中的AOP.所以有必要补充一下动态代理的相关知识. Spring采用JDK动态代理和CGLib动态代 ...
- java中的静态代理和动态代理,入门整理
静态代理和动态代理主要解决的问题是:在直接访问对象时带来的问题,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后 ...
- java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总
若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...
- 一篇文章让你搞懂Java中的静态代理和动态代理
什么是代理模式 代理模式是常用的java设计模式,在Java中我们通常会通过new一个对象再调用其对应的方法来访问我们需要的服务.代理模式则是通过创建代理类(proxy)的方式间接地来访问我们需要的服 ...
- Java中的代理模式--静态代理和动态代理本质理解
代理模式定义:为其他对象提供了一种代理以控制对这个对象的访问. 代理模式的三种角色: Subject抽象主题角色:抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求. Real ...
随机推荐
- 6、图标:icon
1.图标 /* ---html----*/ <ion-content text-center class="icons-basic-page"> <ion-row ...
- spring+hibernate 配置多个数据源过程 以及 spring中数据源的配置方式
spring+hibernate 配置多个数据源过程 以及 spring中数据源的配置方式[部分内容转载] 2018年03月27日 18:58:41 守望dfdfdf 阅读数:62更多 个人分类: 工 ...
- SharePoint - JavaScript Variable & Functions
1. MSOWebPartPageFormName 获取当前form的名称,然后可用document.forms[MSOWebPartPageFormName]来得到当前form: 2. _spPag ...
- Oracle运行依赖的服务
1.Oracle ORCL VSS Writer Service. Oracle卷映射拷贝写入服务,VSS(Volume Shadow Copy Service)能够让存储基础设备(比如磁盘,阵列等) ...
- ArcGIS Engine从服务器(ArcSDE geodatabases)读取数据
从远程服务器读取数据进行处理,直接贴代码: public class ConnectDB { private static String SERVER = "xxx.xxx.xxx.xxx& ...
- Android NestedScrollView与RecyclerView嵌套,以及NestedScrollView不会滚动到屏幕顶部解决
①NestedScrollView与RecyclerView嵌套,导致滚动惯性消失 解决:mRecyclerView.setNestedScrollingEnabled(false); ②Nested ...
- RecycleView + SwipeRefreshLayout 实现下拉刷新和底部自动加载
前段时间项目里面使用了RecycleView 但是里面的刷新和加载都是框架里面封装好的,直接使用 这几天比较闲就自己来实现以下. 因为SwipeRefreshLayout是一个下拉刷新控件所有直接和R ...
- HTML <meta> Attribute
HTML <meta> Attribute http-equiv 定义和用法 The http-equiv attribute provides an HTTP header for th ...
- May 24th 2017 Week 21th Wednesday
Always remember that you are absolutely unique. 永远记住,你是独一无二的. I am unique, in the way that all I do ...
- vuejs 开发中踩到的坑
用 v-for 循环式 每个item的值相等的情况下,会影响v-model的双向绑定: Modal 组件开发,主要用slot 标签来实现 <template> <transitio ...