静态代理 和 JDK动态代理
接口:UserManager.java
1 package com.springdemo.manager;
2
3 public interface UserManager {
4 public void add(String name,String password);
5 public void delete(String name);
6 public int count();
7 }
类:UserManagerImpl.java
1 package com.springdemo.manager;
2
3 public class UserManagerImpl implements UserManager {
4
5 public void add(String name, String password) {
6 System.out.println(" do add user ... ");
7 }
8
9 public void delete(String name) {
10 System.out.println(" do delete user ... ");
11 }
12
13 public int count() {
14 return 10;
15 }
16 }
问题:现要求在调用UserManager的每个方法时,都要检查操作员权限,但不能改变UserManagerImpl的代码。
静态代理实现:
静态代理类:UserManagerProxy.java
package com.springdemo.manager;
public class UserManagerProxy implements UserManager {
private UserManagerImpl impl;
public UserManagerProxy() {
this.impl = new UserManagerImpl();
}
public void add(String name, String password) {
checkPower();
this.impl.add(name, password);
}
public void delete(String name) {
checkPower();
this.delete(name);
}
public int count() {
checkPower();
return this.impl.count();
}
private void checkPower() {
System.out.println("check manager power ....");
}
}
这就是静态代理的思想。
测试代码:
1 package com.springdemo.client;
2
3 import com.springdemo.manager.UserManager;
4 import com.springdemo.manager.UserManagerProxy;
5
6
7 public class Client {
8 public static void main(String[] args) {
9 UserManager userManager = new UserManagerProxy();
10 userManager.add("name..", "pwd..");
11 }
12
13 }
静态代理存在一个问题,比如,当我们在被代理的类中增加了一个方法,代理类中也要增加相应方法。
为此,JDK中提供了动态代理接口。
Jdk动态代理:
我们只需要写一个自定义的调用处理器(实现接口java.lang.reflect.InvokationHandler),然后使用类java.lang.reflect.Proxy中的静态方法 newProxyInstance 来为需要被代理的类自动生成代理类(这个代理类是自动成得,不可见得),并把这个代理类当做原先的类使用即可。
调用处理器类:UserManagerHandler.java
1 package com.springdemo.manager;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5
6 public class UserManagerHandler implements InvocationHandler {
7
8 private Object target;
9
10 public UserManagerHandler(Object target){
11 this.target = target;
12 }
13
14 /**
15 * (自动生成的)代理类将自动用这个方法这执行我们调用的方法。所以我们可以在这里插入我们想执行的代码。
16 * 这个方法是代理类调用的,所以以下参数也是代理类传的。它们的分别是:
17 * @param proxy 调用的代理类(就是自动生成的代理类的实例)
18 * @param method 我们调用的方法
19 * @param args 我们调用方法时传的参数
20 */
21 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
22 try{
23 checkPower();
24
25 //这里会执行我们调用的方法,如果被调用方法没有返回值(void申明),这里返回null
26 Object returnValue = method.invoke(target, args);
27 return returnValue;
28 }catch(Exception e){
29 throw e;
30 }
31 }
32
33 private void checkPower() {
34 System.out.println("check manager power ....");
35 }
36 }
37
测试代码:
1 package com.springdemo.client;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Proxy;
5
6 import com.springdemo.manager.UserManager;
7 import com.springdemo.manager.UserManagerHandler;
8 import com.springdemo.manager.UserManagerImpl;
9
10
11 public class Client {
12 public static void main(String[] args) {
13 // UserManager userManager = new UserManagerProxy();
14 // userManager.add("name..", "pwd..");
15
16 UserManager userManager = new UserManagerImpl();
17 ClassLoader loader = Client.class.getClassLoader();
18 Class<?>[] interfaces = {UserManager.class};
19 InvocationHandler h = new UserManagerHandler(userManager);
20 userManager = (UserManager)Proxy.newProxyInstance(loader, interfaces, h);
21 userManager.add("name..", "pwd..");
22 userManager.count();
23 }
24
25 }
优化UserManagerHandler.java
1 package com.springdemo.manager;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Proxy;
6
7 public class UserManagerHandler implements InvocationHandler {
8
9 private Object target;
10
11
12 // public UserManagerHandler(Object target){
13 // this.target = target;
14 // }
15
16 public Object newProxy(Object target){
17 this.target = target;
18 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
19 }
20
21 /**
22 * (自动生成的)代理类将自动用这个方法这执行我们调用的方法。所以我们可以在这里插入我们想执行的代码。
23 * 这个方法是代理类调用的,所以以下参数也是代理类传的。它们的分别是:
24 * @param proxy 调用的代理类(就是自动生成的代理类的实例)
25 * @param method 我们调用的方法
26 * @param args 我们调用方法时传的参数
27 */
28 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
29 try{
30 checkPower();
31
32 //这里会执行我们调用的方法,如果被调用方法没有返回值(void申明),这里返回null
33 Object returnValue = method.invoke(target, args);
34 return returnValue;
35 }catch(Exception e){
36 throw e;
37 }
38 }
39
40 private void checkPower() {
41 System.out.println("check manager power ....");
42 }
43 }
44
测试代码:
1 package com.springdemo.client;
2
3 import com.springdemo.manager.UserManager;
4 import com.springdemo.manager.UserManagerHandler;
5 import com.springdemo.manager.UserManagerImpl;
6
7
8 public class Client {
9 public static void main(String[] args) {
10 // UserManager userManager = new UserManagerProxy();
11 // userManager.add("name..", "pwd..");
12
13 UserManager userManager = new UserManagerImpl();
14 UserManagerHandler h = new UserManagerHandler();
15 userManager = (UserManager)h.newProxy(userManager);
16 userManager.add("name..", "pwd..");
17 userManager.count();
18 }
19
20 }
21
以这个动态代理的例子,说明一下Spring中AOP术语:
1.切面(Aspect),对应UserMenagerHandler这个类。
2. 连接点(JoinPoint),切面应用在某个方法上,这个方法就是连接点,如:UserManagerImpl类中的add()方法。
3. 处理逻辑(Advice),对应UserMenagerHandler中的 checkPower() 方法。
(处理逻辑(Advice)通常有:Before(前置通知),After(后置通知),Around(环绕通知),Throw(异常通知))
4. 切点(PointCut),连接点的集合,审明处理逻辑在哪些方法上应用。
5. 目标对象,对应UserManagerImpl的实例。
6. 把Aspect应用到Manager的方法上,叫置入。