黑马程序员--设计模式之代理模式 02
2014-05-08 15:16
453 查看
------- android培训、java培训、期待与您交流!
----------
代理模式
1.代理的概念
代理模式即Proxy Pattern,23种java常用设计模式之一。代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,
而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式的思想是为了提供额外的处理
或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象
进行通信。代理可分为静态代理和动态代理。
2.静态代理代码实现
/** * 用户模块数据库操作接口 */ public interface IUserDao { /** * 添加用户 */ public void addUser(); /** * 删除用户 */ public void delUser(); } public class UserDaoMySqlImpl implements IUserDao { @Override public void addUser() { System.out.println("UserDaoImpl--Mysql-addUser()"); } @Override public void delUser() { System.out.println("UserDaoImpl--Mysql-delUser()"); } } public class UserDaoProxyImpl implements IUserDao { public IUserDao userDao; public UserDaoProxyImpl(IUserDao dao){ this.userDao = dao; } @Override public void addUser() { userDao.addUser(); } @Override public void delUser() { userDao.delUser(); } } /** * 测试Main方法 */ public class TestMain { /** * 测试main方法 * @param args */ public static void main(String [] args){ IUserDao dao1 = new UserDaoMySqlImpl(); IUserDao dao2 = new UserDaoProxyImpl(dao1); dao2.addUser(); } }
3.动态代理实现
原理 : 使用反射对动态的去获取方法 实现 动态代理的接口public interface HelloWorld { /** * 对外接口 */ public void sayHelloWorld(); } public class HelloWorldImpl implements HelloWorld { /** * 实现类 */ public void sayHelloWorld() { System.out.println("Hello world"); } } public class HelloWorldProxy implements InvocationHandler { /** * 代理对象 */ private Object obj; /** * 构造方法 * @param obj */ public HelloWorldProxy(Object obj){ this.obj = obj; } /** * 默认执行方法 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; doBefore(); result = method.invoke(obj, args); doAfter(); return result; } private void doBefore(){ System.out.println("before method invoke"); } private void doAfter(){ System.out.println("after method invoke"); } } public class TestMain { /** * 测试Main方法 * @param args */ public static void main(String [] args){ HelloWorld helloWorld = new HelloWorldImpl(); HelloWorldProxy hwp = new HelloWorldProxy(helloWorld); HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(helloWorld.getClass().getClassLoader(), helloWorld.getClass().getInterfaces(), hwp); proxy.sayHelloWorld(); } }
4.静态代理与动态代理的比较
1)静态代理由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
2)静态代理只服务于一个接口。而动态代理可以服务于多个接口。例如上述代码中的静态代理实现
的是IUserDao接口,该代理类只服务于该接口,而动态代理HelloWorldProxy实现的是
InvocationHandler接口,其不仅仅可以为 HelloWorld接口服务,也可为其他新增接口服务。
3)静态代理中如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要
实现此方法。增加了代码维护的复杂度。
4)动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的
字节码文件。代理类和委托类的关系是在程序运行时确定。动态代理中的ClassLoader是类装载器类,
负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy
静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是
其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。 每次生成动态代理类
对象时都需要指定一个类装载器对象.
5)动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中
处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理
那样每一个方法进行中转。
5.简单Spring 切面编程实现
注解 + 动态代理 实现1.创建注解类Get
2.创建注解类After
3.创建动态代理类
测试:
4.创建接口
5.实现接口类
6.切面类
7.测试
package spring; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 如果某类中声明了该注释 表示使用切面编程 * @author 李昂志 */ @Retention(RetentionPolicy.RUNTIME) //运行时调用 @Target(value = {ElementType.TYPE }) //只允许生命在类前面 public @interface Get { String classpath(); }
package spring; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 在类的方法后执行该方法 * @author 李昂志 * */ @Retention(RetentionPolicy.RUNTIME) //运行时调用 @Target(value = {ElementType.METHOD}) //只允许声明在方法前面 public @interface After { String methodName();//要加载 }
package spring; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 代理类 动态实现切面编程 * @author 李昂志 * */ public class ProxySpring implements InvocationHandler { private Object obj; public ProxySpring(Object obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Get get = obj.getClass().getAnnotation(Get.class); Object result = null; result = method.invoke(this.obj, args); if(get != null){ get.classpath(); Class c = Class.forName(get.classpath()); Method[] ms = c.getMethods(); for(Method m : ms ){ After a = m.getAnnotation(After.class); if(a != null) { m.invoke(c.newInstance()); } } } return result; } }
package spring; import java.lang.reflect.Proxy; /** * 测试类 * @author 李昂志 */ @Get(classpath = "spring.Aop") public class TestSpring implements A{ @Override public void say() { // TODO Auto-generated method stub System.out.println("I'm say hello world"); } public static void main(String[] args) { A a = new TestSpring(); ProxySpring ps = new ProxySpring(a); A b = (A)Proxy.newProxyInstance(a.getClass().getClassLoader(), a.getClass().getInterfaces(), ps); b.say(); } } /** * 接口 * @author 李昂志 */ interface A{ public void say(); } /** * 切面类 * @author 李昂志 */ class Aop{ //切面方法 @After(methodName = "nothind to do") public void after(){ System.out.println(" 我是 aop after 方法"); } }
------- android培训、java培训、期待与您交流!
----------
相关文章推荐
- 2014年面试题(二)
- 优秀程序员必备图书
- 黑马程序员_关于JAVA中栈和堆,以及由此引发的一些思考
- 程序员也期待完美的爱情
- 面试10大算法汇总+常见题目解答---中文
- 程序员的面试
- 聚美优品前端开发面试题
- 面试集锦
- 一个合格的程序员应该读过哪些书
- 优秀程序员的十个习惯
- 程序员必看的十大电影
- 程序员人生之路
- 黑马程序员_银行业务调度系统
- 【面试题019】二叉树的镜像
- 黑马程序员--Java学习03--Java程序的基本成分、数据类型
- 菜鸟面试第二站(不听劝告,坑了一脸的公司)
- 黑马程序员_交通灯管理系统
- Careercup - Google面试题 - 5765091433644032
- 新浪php工程师面试题
- 女码农献丑-企业智能机器人客服(图灵机器人)