Java静态代理与动态代理

我们经常用的那些诸如springMybatis等框架底层用到了大量的代理模式。可以说如果想进阶Java的高级开发层次,代理模式无论如何是绕不开的。

我们常说的代理模式,主要分为两种:静态代理和动态代理。静态代理是代理静态的代理了指定的类方法,这种方式很简单,但是不够灵活,于是动态代理就应运而生,动态代理可以动态的代理指定类里面的方法,可以在代理类里面做很多的功能,比如Mybatis的Mapper,spring的AOP等等。

今天的代码框架如下:

enter description here

UserServiceStaticProxy:静态代理类
JdkPropxyHandler:Jdk动态代理处理类,实现自InvocationHandler
UserServiceJdkProxy:Jdk动态代理类,方法中用到了JdkPropxyHandler
CGLibInterceptor:CGLib的动态代理拦截器类,实现自MethodInterceptor
UserServiceCGLibProxy:CGLib的动态代理类,里面用到了CGLibInterceptor

1. 静态代理

代理类和被代理类都实现自同一个接口,代理类里面有调用被代理类,而对外提供的实现是代理类。

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
29
package com.songwh.proxydemo.service.impl;

import com.songwh.proxydemo.service.IUserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("UserServiceStaticProxy")
public class UserServiceStaticProxy implements IUserService {

@Resource(name = "UserServiceImpl")
private IUserService target;

@Override
public String select() {
System.out.println("UserServiceStaticProxy:select-start");
String result = target.select();
System.out.println("UserServiceStaticProxy:select-end");
return "UserServiceStaticProxy:select:" + result;
}

@Override
public String update() {
System.out.println("UserServiceStaticProxy:update-start");
String result = target.update();
System.out.println("UserServiceStaticProxy:update-end");
return "UserServiceStaticProxy:update:" + result;
}
}

2. 动态代理

2.1 JDK动态代理

jdk的动态代理类使用也很简单:
只需要如下代码即可,里面的参数都来自被代理对象

1
2
3
4
5
6
7
8
9
10
// 被代理的对象
UserServiceImpl userService = new UserServiceImpl();
// 取到被代理对象的类加载器
ClassLoader classLoader = userService.getClass().getClassLoader();
// 获取代理对象的接口
Class<?>[] interfaces = userService.getClass().getInterfaces();
// 获取代理处理器
JdkPropxyHandler jdkPropxyHandler = new JdkPropxyHandler(userService);
// 通过Proxy工具获取新的代理实例,这里有一点需要注意的是返回的对象一定要强转为接口对象
return (IUserService) Proxy.newProxyInstance(classLoader, interfaces, jdkPropxyHandler);

代理类的完成代码:

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

package com.songwh.proxydemo.service.impl;

import com.songwh.proxydemo.handler.JdkPropxyHandler;
import com.songwh.proxydemo.service.IUserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.lang.reflect.Proxy;

@Configuration
public class UserServiceJdkProxy {

@Resource(name = "UserServiceImpl")
private IUserService userService;

@Bean("UserServiceJdkProxy")
public IUserService getInstance() {
UserServiceImpl userService = new UserServiceImpl();
ClassLoader classLoader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
JdkPropxyHandler jdkPropxyHandler = new JdkPropxyHandler(userService);
return (IUserService) Proxy.newProxyInstance(classLoader, interfaces, jdkPropxyHandler);
}
}

代理处理器,实现自InvocationHandler

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
29
30
package com.songwh.proxydemo.handler;

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

public class JdkPropxyHandler implements InvocationHandler {

Object target;

public JdkPropxyHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
befor();
// 这里通过Method来调用被代理对象,记得此处一定是传入target,否则会导致死循环。
Object invoke = method.invoke(target, args);
after();
return "UserServiceDynamicProxy:" + invoke;
}

private void befor() {
System.out.println("LogHandler:befor");
}

private void after() {
System.out.println("LogHandler:after");
}
}

2.2 CGLib动态代理

CGLib的动态代理更简单,CGLib的代理原理是采用继承的方式,子类调用父类的方法。主需要如下一行代码即可实现一个cglib的动态代理:

enter description here

1
(IUserService) Enhancer.create(userService.getClass(), new CGLibInterceptor());

完成的类方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.songwh.proxydemo.service.impl;

import com.songwh.proxydemo.handler.CGLibInterceptor;
import com.songwh.proxydemo.service.IUserService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

@Configuration
public class UserServiceCGLibProxy {

@Resource(name = "UserServiceImpl")
private IUserService userService;

@Bean("UserServiceCGLibProxy")
public IUserService getInstance() {
return (IUserService) Enhancer.create(userService.getClass(), new CGLibInterceptor());
}
}

CGLib的方法拦截器实现类如下:

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
package com.songwh.proxydemo.handler;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLibInterceptor implements MethodInterceptor {

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
befor();
// 此处需要注意一定是调用父类方法,invokeSuper,否则代理不成功
Object result = methodProxy.invokeSuper(o, objects);
after();
return "LogInterceptor:" + result;
}

private void befor() {
System.out.println("LogInterceptor:befor");
}

private void after() {
System.out.println("LogInterceptor:after");
}
}
-------------本文结束感谢您的阅读-------------