锁定老帖子 主题:从JDK动态代理到SPRING AOP
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-11-03
最后修改:2012-11-05
代理模式 首先创建接口: package org.iti.wxl.staticproxy; /** * 接口 */ public interface UserService { public void saveUser(); public void deleteUser(); }
对接口的实现:(这里就不连接数据库了,只做简单的实例) package org.iti.wxl.staticproxy; public class UserServiceImpl implements UserService { @Override public void saveUser() { System.out.println("==user saved!=="); } @Override public void deleteUser() { System.out.println("==user deleted!=="); } }
代理类: package org.iti.wxl.staticproxy; public class UserServiceImplProxy implements UserService { private UserServiceImpl userServiceImpl; public UserServiceImplProxy(UserServiceImpl userServiceImpl) { this.userServiceImpl = userServiceImpl; } @Override public void saveUser() { System.out.println("save begin!"); userServiceImpl.saveUser(); System.out.println("save end!"); } @Override public void deleteUser() { System.out.println("delete begin!"); userServiceImpl.deleteUser(); System.out.println("delete end!"); } } 代理类同样实现了UserService接口,代理类持有UserServiceImpl,并且重写了UserService接口里的方法,在方法里添加了逻辑。
测试方法: package org.iti.wxl.staticproxy; public class StaticProxy { //静态代理方法测试 public static void main(String[] args) { UserServiceImpl userServiceImpl = new UserServiceImpl(); UserServiceImplProxy userServiceImplProxy = new UserServiceImplProxy(userServiceImpl); userServiceImplProxy.saveUser(); System.out.println("============="); userServiceImplProxy.deleteUser(); } } 把创建的UserServiceImpl交给代理类UserServiceImplProxy,由它的实例执行数据逻辑操作。
方法运行结果如下: save begin! ==user saved!== save end! ============= delete begin! ==user deleted!== delete end! 代理类中添加的逻辑在方法运行时被执行了。
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。 解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
jdk动态代理 jdk动态代理中包含一个类和一个接口,用到了java的反射机制: public interface InvocationHandler { public Object invoke(Object proxy,Method method,Object[] args); } 参数说明: 下面用代码说明jdk动态代理的使用 接口类: package org.iti.wxl.dynamicproxy; public interface UserService { public void addUser(); public void deleteUSer(); }
对接口的实现: package org.iti.wxl.dynamicproxy; public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("==add user=="); } @Override public void deleteUSer() { System.out.println("==delete user=="); } }
代理类: package org.iti.wxl.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class UserServiceImplProxy implements InvocationHandler { private Object target; public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("user add begin!"); result = method.invoke(target, args); System.out.println("user add end!"); return result; } } 代理类主要负责两项功能:1、把Object转化成代理类的一个实现;2、为方法添加逻辑(如日志,性能测试等)。
测试类: package org.iti.wxl.dynamicproxy; public class DynamicProxy { public static void main(String[] args) { UserServiceImplProxy proxy = new UserServiceImplProxy(); UserService userServiceProxy = (UserService)proxy. bind(new UserServiceImpl()); userServiceProxy.addUser(); System.out.println("========"); userServiceProxy.deleteUSer(); } } 测试结果: user add begin! ==add user== user add end! ======== user add begin! ==delete user== user add end!
分析: 可以将InvocationHandler接口的子类想象成一个代理的最终操作类。 在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器: 这三个类的继承关系是Extendsion ClassLoader继承Booststrap ClassLoader,AppClassLoader继承Booststrap ClassLoader,每加载一个类都现有父类加载,父类没有再用其孩子类加载,保证了安全性。另外我们也可以写自己的类加载器,为类加载器加密等。
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
spring AOP AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。Spring主要通过代理来实现AOP。 切面(Aspect):对横切关注点的抽象(类似类对对象的抽象) 通知(Advice):在特定的连接点,AOP框架执行的动作.前置/后置/例外/最终/环绕通知。 示例代码: 接口类: package org.iti.wxl.springaop; public interface UserService { public String getUser(String userId); public void addUser(); }
对接口的实现: package org.iti.wxl.springaop; public class UserServiceImpl implements UserService { @Override public String getUser(String userId) { System.out.println("this is getUser() method!"); return "user"; } @Override public void addUser() { System.out.println("this is addUser() method!"); } }
定义切面: package org.iti.wxl.springaop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class MyInterceptor { @Pointcut("execution(* org.iti.wxl.springaop..*.*(..))") private void pointCutmethod(){ } @Before("pointCutmethod() && args(userId)") public void doBefore(String userId){ System.out.println("前置通知 " + userId); } @AfterReturning("pointCutmethod()") public void doAfterReturning(){ System.out.println("后置通知"); } @AfterThrowing("pointCutmethod()") public void doAfterException(){ System.out.println("异常通知"); } @After("pointCutmethod()") public void doAfter(){ System.out.println("最终通知"); } @Around("pointCutmethod()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("环绕开始"); Object object = pjp.proceed(); System.out.println("环绕结束"); return object; } } 说明: 第一个*表示方法的返回值,这里使用通配符,只有返回值符合条件的才拦截(!void表示有返回值)。
配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 使用 annotation --> <context:annotation-config /> <!-- 启用aop --> <aop:aspectj-autoproxy proxy-target-class="true" /> <bean id="myInterceptor" class="org.iti.wxl.springaop.MyInterceptor"/> <bean id="userService" class="org.iti.wxl.springaop.UserServiceImpl"/> </beans> 测试类: package org.iti.wxl.springaop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringAOP { public static void main(String[] args) { ApplicationContext cxt = new ClassPathXmlApplicationContext("bean.xml"); UserService userService = (UserService)cxt.getBean("userService"); userService.getUser("user1"); System.out.println("==========="); userService.addUser(); } } 运行结果: 前置通知 user1 环绕开始 this is getUser() method! 后置通知 最终通知 环绕结束 =========== 环绕开始 this is addUser() method! 后置通知 最终通知 环绕结束 在项目开发中,AOP主要用来配置spring的声明式事务管理,它还可用在日志管理,性能监测等。它为程序员编程提供了一种新思路,我们可以不断去发现它的新用途。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-11-03
第一次在论坛发帖子,有不妥的地方还请多多包涵! |
|
返回顶楼 | |
发表时间:2012-11-05
静态代理,一般在需要代理对象数量较少时,可以使用。至于动态代理,是spring AOP实现的其中一种方法,另外一种方法,是通过生成继承类的方式来实现。
如果可以的话,能否对帖子中的内容再进一步说明,比如类加载机制是怎么个实现过程之类的。 (附;楼主的贴子内容和我曾经看过的一本书上的内容,有很大的类同哦。希望是巧合^_^) |
|
返回顶楼 | |
发表时间:2012-11-05
类的加载机制可以看看这两个帖子:http://www.iteye.com/topic/117628;http://www.blogjava.net/hao446tian/archive/2011/03/14/346183.html,希望对你有帮助! |
|
返回顶楼 | |
发表时间:2012-11-05
JVM装载类时使用“全盘负责委托机制”,“全盘负责”是指在当一个ClassLoader装载一个类时,除非显示的使用另一个ClassLoader,该类所依赖及应用的类也由这个ClassLoader载入;“委托机制”是指先委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全角度考虑的,试想如果有人编写了一个恶意的基础类(如java.lang.String)并装载到JVM中将会引起多么可怕的后果。但是由于有了全盘负责制,java.lang.String永远是有根装载器来装载的,这样就避免了上述事件的发生。(来自《精通Spring2.0-企业应用开发详解》) |
|
返回顶楼 | |
浏览 7319 次