NOTE
6.3 代理模式
1. 定义 不改变原有代码的基础上为类或者函数增加新功能。 我不想做跟我业务无关的东西 2. uml 3. Java 3.1. 静态代理 代理类在编译时生成,需要程序员自己手写 3.1.1. client 3.1.2. 代理 3.1.3. 被代理 3.2. 动态代理 代理类在运行时生成, 利用的ja
这是历史学习笔记,可能存在过时或不完整的理解。
1. 定义
不改变原有代码的基础上为类或者函数增加新功能。
我不想做跟我业务无关的东西
2. uml
3. Java
3.1. 静态代理
代理类在编译时生成,需要程序员自己手写
3.1.1. client
public class Client
{
public static void main(String[] args)
{
Proxy proxy = new Proxy(new RealImpl());
proxy.run();
}
}
3.1.2. 代理
public class Proxy implements Real
{
private Real real;
public Proxy(Real real)
{
this.real = real;
}
public void run()
{
System.out.println("运行之前");
this.real.run();
System.out.println("运行之后");
}
}
3.1.3. 被代理
public interface Real
{
void run();
}
public class RealImpl implements Real
{
@Override
public void run()
{
System.out.println("Real run");
}
}
3.2. 动态代理
代理类在运行时生成, 利用的java的反射机制
3.2.1. jdk 动态代理
使用接口实现动态代理,需要目标类有个接口
3.2.1.1. client
public class Client
{
public static void main(String[] args)
{
Proxy proxy = new Proxy(new RealImpl());
Real obj = (Real) proxy.getProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Real.class}, proxy);
obj.run();
}
}
3.2.1.2. 代理
//代理类不需要实现被代理类的接口
public class Proxy implements InvocationHandler
{
private Real real;
public Proxy(Real real)
{
this.real = real;
}
//为目标对象生成代理对象
public Object getProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
return java.lang.reflect.Proxy.newProxyInstance(loader, interfaces, h);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
System.out.println("*************************");
method.invoke(real, args);
System.out.println("*************************");
return null;
}
}
3.2.1.3. 被代理
public interface Real
{
void run();
}
public class RealImpl implements Real
{
@Override
public void run()
{
System.out.println("Real run");
}
}
3.2.2. cglib
通过继承目标类来实现,不能对final修饰的类进行代理
3.2.2.1. client
public class Client
{
public static void main(String[] args)
{
Proxy proxy = new Proxy(new Real());
Real obj = (Real) proxy.getProxyInstance();
obj.run();
}
}
3.2.2.2. 代理
public class Proxy implements MethodInterceptor
{
private Real real;
public Proxy(Real real)
{
this.real = real;
}
//为目标对象生成代理对象
public Object getProxyInstance() {
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(real.getClass());
//设置回调函数
en.setCallback(this);
//创建子类对象代理
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable
{
System.out.println("run之前");
// 执行目标对象的方法
Object returnValue = method.invoke(real, objects);
System.out.println("run之后");
return null;
}
}
3.2.2.3. 被代理
public class Real
{
public void run()
{
System.out.println("Real run");
}
}
3.3. Spring AOP
- 如果目标类实现了接口 那么默认情况使用JDK动态代理 也可以强制使用CGLIB
- 如果目标类没有实现接口 那么使用CGLIB
4. Golang
4.1. 被代理
/*接口*/
type IReal interface {
Do()
}
/*具体对象*/
type Real struct {
}
func NewReal() *Real {
return &Real{}
}
func (r Real) Do() {
fmt.Println("具体对象 doing...")
}
4.2. 代理
/*代理对象*/
type Proxy struct {
Real IReal
}
func NewProxy(real IReal) *Proxy {
return &Proxy{Real: real}
}
func (p Proxy) Do() {
fmt.Println("before")
p.Real.Do()
fmt.Println("after")
}
4.3. client
func main() {
real := 代理.NewReal()
proxy := 代理.NewProxy(real)
proxy.Do()
}
5. 实例
5.1. 缓存代理

- cache/cache.go
package cache
import (
"context"
"fmt"
lru "github.com/hnlq715/golang-lru"
)
var ActIdCache *lru.ARCCache
func init() {
ActIdCache, _ = lru.NewARC(100)
}
type CacheableFunc = func(ctx context.Context, key fmt.Stringer) (interface{}, error)
//缓存由fn计算的value,如果fn返回error那么不缓存
func WithCache(lruCache *lru.ARCCache,
fn func(ctx context.Context, key fmt.Stringer) (interface{}, error),
ctx context.Context, key fmt.Stringer) (interface{}, error) {
//从缓存中查,有则返回
if value, ok := lruCache.Get(key.String()); ok {
fmt.Printf("WithCache: get value %v from cache for key %v\n", value, key.String())
return value, nil
}
//缓存中没有,那么调用目标函数。调用成功同时添加到缓存中
value, err := fn(ctx, key)
if err == nil {
fmt.Printf("WithCache: add value %v to cache for key %v\n", value, key.String())
lruCache.Add(key.String(), value)
}
return value, err
}
//调用目标函数失败之后降级使用缓存
func WithFallbackCache(lruCache *lru.ARCCache,
fn func(ctx context.Context, key fmt.Stringer) (interface{}, error),
ctx context.Context, key fmt.Stringer) (interface{}, error) {
//先调用目标函数,调用成功同时添加到缓存中
value, err := fn(ctx, key)
if err == nil {
fmt.Printf("WithFallbackCache: add value %v to cache for key %v\n", value, key.String())
lruCache.Add(key.String(), value)
return value, nil
}
//目标函数调用失败,那么降级使用缓存
if value, ok := lruCache.Get(key.String()); ok {
fmt.Printf("WithFallbackCache: get value %v from cache for key %v\n", value, key.String())
return value, nil
}
return value, err
}
- model/model.go
package model
import "fmt"
type ActIdCacheParam struct {
Source string
}
func NewActIdCacheParam(source string) *ActIdCacheParam {
return &ActIdCacheParam{Source: source}
}
func (a *ActIdCacheParam) String() string {
return fmt.Sprintf("%s", a.Source)
}
- service/service.go
package service
import (
"context"
"fmt"
"strconv"
"test/proxy/cache"
"test/proxy/model"
)
//根据source获取actId
//使用cache.CacheableFunc定义表示这个函数实现了可缓存的接口
var getActIdBySourceFunc cache.CacheableFunc = func(ctx context.Context, key fmt.Stringer) (interface{}, error) {
actIdCacheParam := key.(*model.ActIdCacheParam)
actId, err := strconv.Atoi(actIdCacheParam.Source)
return actId, err
}
func GetActIdBySource(source string) (int, error) {
cachedValue, err := cache.WithCache(cache.ActIdCache, getActIdBySourceFunc, context.Background(),
model.NewActIdCacheParam(source))
if err != nil {
return 0, err
}
actId := cachedValue.(int)
return actId, nil
}
- proxy_test.go
package proxy
import (
"test/proxy/service"
"testing"
)
func TestProxy(t *testing.T) {
service.GetActIdBySource("11")
service.GetActIdBySource("11")
}