java动态代理

代理模式

说到动态代理和静态代理,我们不得不说的就是代理模式,那么代理模式是什么呢?它是一种常用的设计模式,属于结构型。

代理模式的目的就是为其他对象提供一个代理以控制对某个对象的访问。

image

为了让代理类能使用委托类的方法名就能实现功能,让访问者用起来没有区别,都需要让代理类和委托类实现同一接口,能有效控制对
委托类对象的直接访问,也可以很好地隐藏和保护委托类对象。

静态代理

静态代理是事先知道委托类的对象类型。

具体实现类,委托类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Man implements User {  

@Override
public void addUser(String userId, String userName) {
System.out.println("Man.addUser");
}

@Override
public void delUser(String userId) {
System.out.println("Man.delUser");
}

@Override
public String findUser(String userId) {
System.out.println("Man.findUser");
return "张三";
}

@Override
public void modifyUser(String userId, String userName) {
System.out.println("Man.modifyUser");

}
}

代理类

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
public class UserProxy implements User {  

// 目标对象
private Man user;

public UserProxy(Man user){
this.user=user;
}

@Override
public void addUser(String userId, String userName) {
try{
//添加打印日志
System.out.println("start-->addUser()");
user.addUser(userId, userName);
//添加用户成功
System.out.println("success-->addUser()");
}catch(Exception e){
//添加用户失败
System.out.println("error-->addUser()");
}
}

@Override
public void delUser(String userId) {
user.delUser(userId);
}

@Override
public void modifyUser(String userId, String userName) {
user.modifyUser(userId,userName);
}

}

测试类

1
2
3
4
5
6
7
public class Test {  

public static void main(String[] args){
User user=new UserProxy(new Man());
user.addUser("1314", "张三");
}
}

静态代理有很大的限制,因为每个委托类都有不同的功能,也就是说有不同的接口,而让代理类要代理这些类,要么类上面写
很多接口,要么就是创建很多不同的代理类。这就增加了很多复杂性,并且代码重复很多。

动态代理

静态代理中我们知道了如果要代理很多不同的类,静态是不可用的。所以动态代理出现了。

动态代理使用反射的原理来解决问题的。需要用到java.lang.reflect.InvocationHandler接口和 java.lang.reflect.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
public class Man implements User {  

@Override
public void addUser(String userId, String userName) {
System.out.println("Man.addUser");
}

@Override
public void delUser(String userId) {
System.out.println("Man.delUser");
}

@Override
public String findUser(String userId) {
System.out.println("Man.findUser");
return "张三";
}

@Override
public void modifyUser(String userId, String userName) {
System.out.println("Man.modifyUser");

}
}

代理类

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
public class UserProxy implements InvocationHandler {  

// 目标对象
private Object targetObject;
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//关联的这个实现类的方法被调用时将被执行
/*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret=null;
try{
/*原对象方法调用前处理日志信息*/
System.out.println("satrt-->>");

//调用目标方法
ret=method.invoke(targetObject, args);
/*原对象方法调用后处理日志信息*/
System.out.println("success-->>");
}catch(Exception e){
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}

}
1
2
3
4
5
6
7
8
public class Test {  

public static void main(String[] args){
UserProxy proxy=new UserProxy();
User user=(User)proxy.newProxyInstance(new Man());
user.addUser("1111", "张三");
}
}

不过使用反射效率小,且很耗资源,所以一般都使用第三方库CGLib来实现,spring的aop原理就是使用反射加
上CGLib来实现的。