说说java的三种代理方法

想想如果你需要维护一个方法,方法里面写满了很多复杂的逻辑判断之类的,而你要维护的仅仅是一个参数的变动或者是记录日志,安全检查之类的,那么使用代理方式会不会好一点,下面就说说java的三种代理方式,分别是静态代理和两个动态代理,还会演示下代理工厂模式。

静态代理

适用方法:适用接口方法,且代理方法需要实现同一接口

使用场景:有一个书店,每天都会新增书籍上架,然而久而久之,上架的书很多乱七八糟的,需要过滤掉,所以在新增书籍的时候,要有一位上架员,在新增书籍的时候,审核过滤掉这些书籍,不予上架。

接口类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.wwk.springAop.staticproxy;

/**
* JDK静态代理
* 书店接口
*/
public interface IBookShop {

/**
* 新增书籍
* @param bookName
*/
void addBook(String bookName);
}

实现类

1
2
3
4
5
6
7
8
9
10
package com.wwk.springAop.staticproxy;


public class BookShopImpl implements IBookShop {

@Override
public void addBook(String bookName) {
System.out.println("新增书籍:"+bookName);
}
}

代理类

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
31
package com.wwk.springAop.staticproxy;

/**
* 静态代理
* 通过实现同样的类进行代理,达到增强效果
* 这个代理入口就如同增加了一个书店上架员角色
*/
public class BookShopStaticProxy implements IBookShop{

private BookShopImpl BookServiceImpl = new BookShopImpl();

/**
* 上架员开始新增书籍
*/
@Override
public void addBook(String bookName) {

//判断书籍是否符合规范
if (bookName.equals("葫芦小金刚")) {
System.out.println("该书籍不符合规范,不予上架");
}else {
BookServiceImpl.addBook(bookName);
}
}

public static void main(String[] args) {
IBookShop bookShop = new BookShopStaticProxy();
bookShop.addBook("大灰狼");
bookShop.addBook("葫芦小金刚");
}
}

JDK的动态代理:proxy

适用方法:适用接口方法,且代理方法需要实现同一接口

使用场景:小明出来工作,每天都吃方便面,但是生日当天,小明吃的是无敌海鲜麻辣烫

接口类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.wwk.springAop.proxy;

/**
* JDK 动态代理类
* 吃饭接口,代理类
*/
public interface IEat {

/**
* 开始吃饭
* dishName 菜名
*/
void eat(String dishName);

}

实现类

1
2
3
4
5
6
7
8
9
10
package com.wwk.springAop.proxy;


public class EatImpl implements IEat {

@Override
public void eat(String dishName) {
System.out.println("开始吃饭,小明今天吃:"+dishName);
}
}

代理类

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.wwk.springAop.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
* 吃饭的代理方法
* jdk动态代理实现,此代理只能代理实现了接口的方法
* 继承接口:InvocationHandler
* 实现方法:invoke
*/
public class EatProxy implements InvocationHandler{

//代理对象
private EatImpl eatImpl = new EatImpl();

//生日日期
private static String BIRTHDAY = "02-16";

/**
* 代理方法参数说明
* Object 代理对象引用,可能为空
* Method 当前的执行方法
* Object[] 参数数组
*/
@Override
public Object invoke(Object arg0, Method method, Object[] values)
throws Throwable {

String dishName = values[0].toString();

//判断方法
if ("eat".equals(method.getName())) {

//判断日期,是否生日,是则开始加菜
Date currentDate = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd");

if (dateFormat.format(currentDate).equals(BIRTHDAY)) {
dishName = "无敌海鲜麻辣烫";
}
}
return method.invoke(eatImpl, dishName);
}



public static void main(String[] args) {

/**
* 代理目的:如果是生日就不吃方便面了,吃麻辣烫
* ClassLoader 代理类的加载器: getClassLoader
* Class[] 代理类字节码数组: getInterfaces
* InvocationHandler 增强代理方法
*/
IEat eatService = (IEat) Proxy.newProxyInstance(
EatImpl.class.getClassLoader(),EatImpl.class.getInterfaces(),new EatProxy());

eatService.eat("方便面");
}

}

CGLIB的动态代理

适用方法:除静态方法外,都适用,且代理方法不需要实现同一接口

使用场景:有一个书店,每天都会新增书籍上架,然而久而久之,上架的书很多乱七八糟的,需要过滤掉,所以在新增书籍的时候,要有一位上架员,在新增书籍的时候,审核过滤掉这些书籍,不予上架。

方法类

1
2
3
4
5
6
7
8
9
10
11
package com.wwk.springAop.cglib;

/**
* CGLIB 动态代理
*/
public class BookShop {

public void addBook(String bookName){
System.out.println("新增书籍:"+bookName);
}
}

代理类

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.wwk.springAop.cglib;

import java.lang.reflect.Method;

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

/**
* CGLIB 动态代理
* 可代理没有实现接口的方法,注意final和static的方法不能代理
* 需要实现接口:MethodInterceptor
*/
public class BookCglib implements MethodInterceptor{


private BookShop bookService = new BookShop();


/**
* 代理方法,参数说明
* Object 实例的引用,可能为空
* Method 当前执行的方法
* Object[] 执行的方法的参数集合
* MethodProxy 当前执行的方法的代理,一般不用
*
*/
@Override
public Object intercept(Object arg0, Method method, Object[] values,
MethodProxy arg3) throws Throwable {
String book = values[0].toString();

//判断方法,并过滤不良书籍
if ("addBook".equals(method.getName())) {

//过滤掉葫芦小金刚书籍
if (book.equals("葫芦小金刚")) {

//这里可以做异常抛出,外层拦截处理,也可以另外使用参数表示

// throw new ValidationException("该书籍不符合规范,不予上架");
book = "该书籍不符合规范,不予上架";
}
}
return method.invoke(bookService, book);
}


public static void main(String[] args) {

/**
* 通过cglib代理
* 只会拦截非final方法的调用
* Class 代理类
* callback 回调方法
*/
BookShop bookShop = (BookShop)Enhancer.create(BookShop.class, new BookCglib());
bookShop.addBook("大灰狼");
bookShop.addBook("葫芦小金刚");
}

}

proxy代理工厂模式

代理类

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.wwk.springAop.proxyFactory;

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


/**
* proxy代理工厂
* 代理对象采用object代理,通过外部传入
*/
public class MyProxyFactory implements InvocationHandler{

//代理对象
private Object target;


/**
* 对象进厂,加入改造
*/
public MyProxyFactory(Object target) {
this.target = target;
}

/**
* 装载出厂,外部调用
*/
public Object getProxyInstance(){
// this 代指当前对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}

/**
* 改造对象,添加代理方法
*/
@Override
public Object invoke(Object arg0, Method method, Object[] values)
throws Throwable {

System.out.println("这里是工厂,快上车,OVER!");
return method.invoke(target, values);
}


public static void main(String[] args) {

/**
* 测试代理工厂模式
* 装载对象:EatImpl
*/
MyProxyFactory proxyFactory = new MyProxyFactory(new EatImpl());

//获取代理对象
IEat eat = (IEat)proxyFactory.getProxyInstance();
eat.eat("龙虾盖饭");
}
}