还有20天 ,就工作一年了,感觉时间过得真快,当然有的时候也会觉得时间过得很慢,当然觉得慢的时候是觉得怎么离发工资还有那么久的时间,回顾这一年的时间,从刚开始的生手到现在得到一个技术牛人的认可,经历了很多。当然,能让自己进步唯有学习。。自己本身非常喜欢技术,不是很喜欢管理,觉得管理人员的事比较多,比较杂,比较费心、劳心,所以以后还是想走技术路线,争取早日实现自己的一个目标-成为架构师。废话不多说了,今天就来说说代理--proxy
java中的代理按照代理类的生成时期不同分为静态代理和动态代理。
(1)静态代理。由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。下面是静态代理的UML图。
具体的代码如下
1. interface Subject
2. {
3. void request();
4. }
5. class RealSubject implements Subject
6. {
7. public void request()
8. {
9. System.out.println("真实的请求");
10. }
11. }
12. public class Proxy implements Subject
13. {
14. RealSubject realSubject;
15. public void request()
16. {
17. if(realSubject==null)
18. {
19. realSubject=new RealSubject();
20. }
21. realSubject.request();
22. }
23.
24. public static void main(String[] args) {
25. new Proxy().request();
26. }
27. }
(2)动态代理。动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性。想必做java web开发的,会经常用到Spring,而Spring的2大核心之一是Spring AOP,Spring AOP就是利用动态代理实的(Spring利用动态代理技术实现的最重要的一个功能就是声明式事务)。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。那么接下来就利用动态代理实现上面的例子
1. import java.lang.reflect.InvocationHandler;
2. import java.lang.reflect.Method;
3. import java.lang.reflect.Proxy;
4.
5. interface Subject {
6. void request();
7. }
8.
9. class RealSubject implements Subject {
10. public void request() {
11. System.out.println("真实的请求");
12. }
13. }
14.
15. public class DynProxy implements InvocationHandler {
16.
17. private Object dele;
18.
19. public DynProxy(Object obj) {
20. this.dele = obj;
21. }
22.
23. public Object invoke(Object proxy, Method method, Object[] args)
24. throws Throwable {
25. doBefore();
26. // 在这里完全可以把下面这句注释掉,而做一些其它的事情
27. Object result = method.invoke(dele, args);
28. after();
29. return result;
30. }
31.
32. private void doBefore() {
33. System.out.println("before....");
34. }
35.
36. private void after() {
37. System.out.println("after....");
38. }
39.
40. public static void main(String[] args) {
41. RealSubject realSubject= new RealSubject();
42. DynProxy dynProxy= new DynProxy(realSubject);
43. Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), dynProxy);
44. subject.request();
45. }
46. }
这是JDK的动态代理,JDK的自动代理只能对接口实现自动代理,从代码当中也可以看出来realSubject.getClass().getInterfaces().JDK动态对接口进行实现,实现的方法是个空方法,那么动态代理又是怎么调用的realSubject相对应的实现方法呢,答案就是InvocationHandler,它关联了实现类,在上面的例子中也就是realSubject,它会调用realSubject相对应的实现方法。
JDK的动态代理有一个特别明显的不足,即只能对接口实现动态代理。cglib(Code Generation Library)的出现则弥补了JDK代理的不足,cglib能够实现对类进行动态代理。下面就用cglib来实现上面的例子。
1. import java.lang.reflect.Method;
2. import net.sf.cglib.proxy.Enhancer;
3. import net.sf.cglib.proxy.MethodInterceptor;
4. import net.sf.cglib.proxy.MethodProxy;
5.
6. class RealSubject {
7. public void request() {
8. System.out.println("真实的请求");
9. }
10. private void privateExample(){
11. System.out.println("这个是私有方法不能被子类继承");
12. }
13.
14. }
15.
16. public class MyMethodInterceptor implements MethodInterceptor {
17.
18. public Object intercept(Object object, Method method, Object[] args,
19. MethodProxy methodProxy) throws Throwable {
20. System.out.println(">>>MethodInterceptor start...");
21. Object result = methodProxy.invokeSuper(object, args);
22. System.out.println(">>>MethodInterceptor ending...");
23. return "hahahh";
24. }
25.
26. public Object createProxy(Class targetClass) {
27. Enhancer enhancer = new Enhancer();
28. enhancer.setSuperclass(targetClass);
29. enhancer.setCallback(new MyMethodInterceptor());
30. return enhancer.create();
31. }
32.
33. public static void main(String[] args) {
34. RealSubject target = new RealSubject();
35. MyMethodInterceptor test = new MyMethodInterceptor();
36. RealSubject proxyTarget = (RealSubject)test.createProxy(RealSubject.class);
37. proxyTarget.request();
38. }
39. }
cglib能实现对类的动态代理,产生的动态代理类是原始类,在上面的例子就是RealSubject的子类,那么又跑回到了java继承体系当中了,private方法 final方法是不能被子类继承和override的,所以这些方法是不会被动态代理的。像上面的方法privateExample(),就不会出现在main函数中的proxyTarget的方法列表中。
JDK动态代理和cglib动态代理的区别
1、JDK动态代理只能对接口实现动态代理,而cglib能对类实现动态代理
2、JDK动态代理生成动态代理类的速度或者说效率要比cglib快,但是生成后的动态代理类的效率则是cglib高,一般会高十倍以上,所以如果在Spring中使用动态代理,而Spring中的实例一般都是单例的,所以在Spring中生成动态代理类实例一般选用cglib比较好。这样生成的动态代理类的实例效率高。
闲扯几句:一般类的信息、常量信息会放在jvm内存中的方法区或者说是永久区,如果生成动态代理类过多的话,该区被占用的也就越多,有可能导致该区域的内存溢出(只是有可能,现实当中出现的几率非常小,就顺嘴提一句)。