Java 动态代理作用是什么?

时间:2021-08-09 14:37:25

Java 动态代理作用是什么?

 
1 条评论
分享
 
默认排序按时间排序

19 个回答

133赞同反对,不会显示你的姓名
Java 动态代理作用是什么?Intopass 程序员,近期沉迷于动漫ING
① 首先你要明白静态代理的作用
我们有一个字体提供类,有多种实现(从磁盘,从网络,从系统)
public interface FontProvider {
Font getFont(String name);
} public abstract class ProviderFactory {
public static FontProvider getFontProvider() {
return new FontProviderFromDisk();
}
} public class Main() {
public static void main(String[] args) {
FontProvider fontProvider = ProviderFactory.getFontProvider();
Font font = fontProvider.getFont("微软雅黑");
......
}
}

现在我们希望给他加上一个缓存功能,我们可以用静态代理来完成

public class CachedFontProvider implements FontProvider {
private FontProvider fontProvider;
private Map<String, Font> cached; public CachedFontProvider(FontProvider fontProvider) {
this.fontProvider = fontProvider;
} public Font getFont(String name) {
Font font = cached.get(name);
if (font == null) {
font = fontProvider.getFont(name);
cached.put(name, font);
}
return font;
}
} /* 对工厂类进行相应修改,代码使用处不必进行任何修改。
这也是面向接口编程以及工厂模式的一个好处 */
public abstract class ProviderFactory {
public static FontProvider getFontProvider() {
return new CachedFontProvider(new FontProviderFromDisk());
}
}

当然,我们直接修改FontProviderFromDisk类也可以实现目的,但是我们还有FontProviderFromNet, FontProviderFromSystem等多种实现类,一一修改太过繁琐且易出错。
况且将来还可能添加日志,权限检查,异常处理等功能显然用代理类更好一点。

② 然而为什么要用动态代理?
考虑以下各种情况,有多个提供类,每个类都有getXxx(String name)方法,每个类都要加入缓存功能,使用静态代理虽然也能实现,但是也是略显繁琐,需要手动一一创建代理类。

public abstract class ProviderFactory {
public static FontProvider getFontProvider() {...}
public static ImageProvider getImageProvider() {...}
public static MusicProvider getMusicProvider() {...}
......
}

使用动态代理怎么完成呢?

public class CachedProviderHandler implements InvocationHandler {
private Map<String, Object> cached = new HashMap<>();
private Object target; public CachedProviderHandler(Object target) {
this.target = target;
} public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Type[] types = method.getParameterTypes();
if (method.getName().matches("get.+") && (types.length == 1) &&
(types[0] == String.class)) {
String key = (String) args[0];
Object value = cached.get(key);
if (value == null) {
value = method.invoke(target, args);
cached.put(key, value);
}
return value;
}
return method.invoke(target, args);
}
} public abstract class ProviderFactory {
public static FontProvider getFontProvider() {
Class<FontProvider> targetClass = FontProvider.class;
return (FontProvider) Proxy.newProxyInstance(targetClass.getClassLoader(),
new Class[] { targetClass },
new CachedProviderHandler(new FontProviderFromDisk()));
}
}

③ 这也是为什么Spring这么受欢迎的一个原因
Spring容器代替工厂,Spring AOP代替JDK动态代理,让面向切面编程更容易实现。
在Spring的帮助下轻松添加,移除动态代理,且对源代码无任何影响。

10赞同反对,不会显示你的姓名
Java 动态代理作用是什么?郭无心 做好自己
首先动态代理是设计模式当中代理模式的一种。
首先介绍下代理模式,再介绍Java中的动态代理实践。

1,什么是代理模式?

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。

2,代理模式有什么好处?

在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

3,代理模式一般涉及到的角色有:

抽象角色:声明真实对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

代理角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

真实角色:定义了代理对象所代表的目标对象代理角色所代表的真实对象,是我们最终要引用的对象,定义了代理对象所代表的目标对象。

public abstract class AbstractObject {
//操作
public abstract void operation();
}
public class RealObject extends AbstractObject {
@Override
public void operation() {
//一些操作
System.out.println("一些操作");
}
}
public class ProxyObject extends AbstractObject{
RealObject realObject = new RealObject();
@Override
public void operation() {
//调用目标对象之前可以做相关操作
System.out.println("before");
realObject.operation();
//调用目标对象之后可以做相关操作
System.out.println("after");
}
}
public class Client {

    public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractObject obj = new ProxyObject();
obj.operation();
} }

---------------------------------待续

90赞同反对,不会显示你的姓名
最近正好在看,特来挖坟。
关于动态代理设计模式很可能题主就在不知不觉中使用了,例如Spring中的AOP,Struts2中的拦截器等。

先来看静态代理模式代码:

package test;

public interface Subject
{
public void doSomething();
}
package test;

public class RealSubject implements Subject
{
public void doSomething()
{
System.out.println( "call doSomething()" );
}
}
package test;

public class SubjectProxy implements Subject
{
Subject subimpl = new RealSubject();
public void doSomething()
{
subimpl.doSomething();
}
}
package test;

public class TestProxy
{
public static void main(String args[])
{
Subject sub = new SubjectProxy();
sub.doSomething();
}
}

刚开始我会觉得SubjectProxy定义出来纯属多余,直接实例化实现类完成操作不就结了吗?后来随着业务庞大,你就会知道,实现proxy类对真实类的封装对于粒度的控制有着重要的意义。但是静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。所以引入动态代理来解决此类问题。

先看代码:

package test;

public interface Subject
{
public void doSomething();
}
package test;

public class RealSubject implements Subject
{
public void doSomething()
{
System.out.println( "call doSomething()" );
}
}
package test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyHandler implements InvocationHandler
{
private Object tar; //绑定委托对象,并返回代理类
public Object bind(Object tar)
{
this.tar = tar;
//绑定该类实现的所有接口,取得代理类
return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
tar.getClass().getInterfaces(),
this);
} public Object invoke(Object proxy , Method method , Object[] args)throws Throwable
{
Object result = null;
//这里就可以进行所谓的AOP编程了
//在调用具体函数方法前,执行功能处理
result = method.invoke(tar,args);
//在调用具体函数方法后,执行功能处理
return result;
}
}
public class TestProxy
{
public static void main(String args[])
{
ProxyHandler proxy = new ProxyHandler();
//绑定该类实现的所有接口
Subject sub = (Subject) proxy.bind(new RealSubject());
sub.doSomething();
}
}

看完代码,现在我来回答,动态代理的作用是什么:

  1. Proxy类的代码量被固定下来,不会因为业务的逐渐庞大而庞大;
  2. 可以实现AOP编程,实际上静态代理也可以实现,总的来说,AOP可以算作是代理模式的一个典型应用;
  3. 解耦,通过参数就可以判断真实类,不需要事先实例化,更加灵活多变。

欢迎补充。

27赞同反对,不会显示你的姓名
主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等。

还有一个有趣的作用是可以用作远程调用,比如现在有Java接口,这个接口的实现部署在其它服务器上,在编写客户端代码的时候,没办法直接调用接口方法,因为接口是不能直接生成对象的,这个时候就可以考虑代理模式(动态代理)了,通过Proxy.newProxyInstance代理一个该接口对应的InvocationHandler对象,然后在InvocationHandler的invoke方法内封装通讯细节就可以了。具体的应用,最经典的当然是Java标准库的RMI,其它比如hessian,各种webservice框架中的远程调用,大致都是这么实现的。

10赞同反对,不会显示你的姓名
Java 动态代理作用是什么?蔡洲 阿里巴巴,UC
补充一下。
动态代理是JAVA的一大特性。
动态代理的优势就是实现无侵入式的代码扩展。
目前动态代理主要分为JAVA自己提供的动态代理和CGLIB类似框架。
JAVA自带的动态代理是需要接口的。CGLIB这种则是直接修改字节码。
 
from: https://www.zhihu.com/question/20794107