转-Java实现动态代理

http://www.wuwenliang.net/2018/11/30/%E8%BD%AC-

Java%E5%AE%9E%E7%8E%B0%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/

 

代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

代理

代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

代理可以实现过滤请求、插入横切逻辑等功能,应用场景丰富多彩。

代理的方式分为静态代理和动态代理两种。

静态代理

程序运行前代理类的字节码文件依然存在,需要程序员编写源文件。

  • 缺点:要针对于每一个类撰写代理类;对于单个被代理的类,如果需要被代理的方法很多,又加大了工作量。

  • 优点:直观,可读性较强。

动态代理

程序运行时动态生成代理类的字节码文件,不需要程序员编写代理类java文件。

  • 缺点:由于是运行时动态生成的,因此可读性不是很强;而且受限于被代理类自身的属性(jdk需要提供接口,cglib需要是非私有类)。

  • 优点:代码更加简洁,解放了无谓的编码工作。

实现方式

让你来实现一个代理类,需要哪些上下文,有哪些解决方案?

jdk和cglib两种解决方案。

要生产一个类A的代理类,唯一需要了解的就是生产一个什么类,所以需要类A的接口。

至于如何生产一个class文件,在既定规则下你可以先编写java文件,再编译成class文件。而最好的做法是直接操作字节码文件,jdk操作字节码文件用了反射包里面的接口和类,cglib操作字节码文件用了开源框架asm框架。

代理的图示

![][1]

通过代理层这一中间层,有效的控制对于真实委托类对象的直接访问,同时可以实现自定义的控制策略(Spring的AOP机制),设计上获得更大的灵活性。

JDK的动态代理实现

jdk的动态代理,依赖的是反射包下的InvocationHandler接口,我们的代理类实现InvocationHandler,重写invoke()方法,每当我们的代理类调用方法时,都会默认先经过invoke()方法。

UserService接口

 

1

2

3

4

 

public interface UserService {

public String getName(int id);

public Integer getAge(int id);

}

 

接口的实现类UserServiceImpl

 

1

2

3

4

5

6

7

8

9

10

11

12

 

public class UserServiceImpl implements UserService {

public String getName(int id) {

System.out.println("------getName------");

return "Tom";

}

public Integer getAge(int id) {

System.out.println("------getAge------");

return 10;

}

}

 

UserInvocationHandler.java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class UserInvocationHandler implements InvocationHandler {

private Object target;

UserInvocationHandler() {

super();

}

UserInvocationHandler(Object target) {

super();

this.target = target;

}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if("getName".equals(method.getName())){

System.out.println("++++++before " + method.getName() + "++++++");

Object result = method.invoke(target, args);

System.out.println("++++++after " + method.getName() + "++++++");

return result;

}else{

Object result = method.invoke(target, args);

return result;

}

}

}

 

测试类TestUserInvocationHandler.java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

public class TestUserInvocationHandler {

public static void main(String[] args) {

UserService userService = new UserServiceImpl();

InvocationHandler invocationHandler = new UserInvocationHandler(userService);

UserService userServiceProxy = (UserService) Proxy.newProxyInstance(

userService.getClass().getClassLoader(),

userService.getClass().getInterfaces(),

invocationHandler);

System.out.println(userServiceProxy.getName(1));

System.out.println(userServiceProxy.getAge(1));

}

}

 

运行结果:

![][2]

cglib的动态代理实现

cglib需要的jar包:cglib.jar 和 asm.jar

cglib依赖的是cglib包下的MethodInterceptor接口,每调用代理类的方法,都会调用intercept方法

CglibMethodInterceptor.java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

 

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibMethodInterceptor implements MethodInterceptor {

public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

System.out.println("------before " + methodProxy.getSuperName() + "------");

Object o1 = methodProxy.invokeSuper(o, args);

System.out.println("------after " + methodProxy.getSuperName() + "------");

return o1;

}

}

 

TestCglibMethodInterceptor.java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

 

import net.sf.cglib.proxy.Enhancer;

public class TestCglibMethodInterceptor {

public static void main(String[] args) {

CglibMethodInterceptor cglibProxy = new CglibMethodInterceptor();

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(UserServiceImpl.class);

enhancer.setCallback(cglibProxy);

UserServiceImpl o = (UserServiceImpl) enhancer.create();

o.getName(1);

o.getAge(1);

}

}

 

运行结果:

![][3]

总结

JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用JDK动态代理时只能用接口引用指向代理,而不能用传入的类引用指向代理。

cglib采用的是创建一个继承实现类的子类,用asm库动态修改子类的代码来实现的,所以可以用传入的类引用指向代理类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值