h5网站开发流程图,北京微网站设计开发服务,公司部门主页设计方案,河北建设厅网站设置目录 1. 预备知识-动态代理 1.1 什么是动态代理1.2 动态代理的优势1.3 基于JDK动态代理实现2. AOP 2.1 基本概念2.2 AOP带来的好处3. Spring AOP 3.1 前置通知3.2 后置通知3.3 环绕通知3.4 异常通知3.5 适配器
1. 预备知识-动态代理
1.1 什么是动态代理
动态代理利用Java的反…目录 1. 预备知识-动态代理 1.1 什么是动态代理1.2 动态代理的优势1.3 基于JDK动态代理实现2. AOP 2.1 基本概念2.2 AOP带来的好处3. Spring AOP 3.1 前置通知3.2 后置通知3.3 环绕通知3.4 异常通知3.5 适配器
1. 预备知识-动态代理
1.1 什么是动态代理
动态代理利用Java的反射技术(Java Reflection)生成字节码在运行时创建一个实现某些给定接口的新类也称动态代理类及其实例。
1.2 动态代理的优势
动态代理的优势是实现无侵入式的代码扩展也就是方法的增强让你可以在不用修改源码的情况下增强一些方法在方法的前后你可以做你任何想做的事情甚至不去执行这个方法就可以spring中的AOP是动态代理使用的经典场景。
1.3 基于JDK动态代理实现
在基于JDK的动态代理的实现中有两个重要的类InvocationHandler, Proxy
InvocationHandler 是代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。Proxy JDK中动态生成代理类的工具类
一个动态代理的示例
定义一个接口基于JDK的动态代理只能使用接口
public interface ISubject {void hello(String param);
}为接口定义实现类
public class SubjectImpl implements ISubject {Overridepublic void hello(String param) {System.out.println(hello param);}
}实现一个代理类
public class JDKProxy implements InvocationHandler {private Object target;public JDKProxy(Object target) {this.target target;}//创建代理public Object newProxy() {return (ISubject)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(---------- 在业务方法调用之前可以进行前置增强 ------------);//利用反射机制调用方法invoke为返回值如果没有返回nullObject invoke method.invoke(target, args);System.out.println(---------- 在业务方法调用之前可以进行后置增强 ------------);return invoke;}}编写代理类实际的调用利用Proxy类创建代理之后的Subject类
public class JDKProxyDemo {public static void main(String[] args) {ISubject subject new SubjectImpl();JDKProxy subjectProxy new JDKProxy(subject);ISubject proxyInstance (ISubject)subjectProxy.newProxy();proxyInstance.hello(world);}}运行结果
---------- 在业务方法调用之前可以进行前置增强 ------------
hello world
---------- 在业务方法调用之前可以进行后置增强 ------------2. AOP
2.1 基本概念
连接点 (Joinpoint) 程序执行过程中明确的点如方法的调用或者异常的抛出.目标(Target) 被通知(被代理)的对象如上例中的SubjectImpl通知(Advice) 在某个特定的连接点上执行的动作同时Advice也是程序代码的具体实现例如一个实现日志记录的代码(通知有些书上也称为处理)可以理解为AOP真正要实现的功能代理(Proxy) 将通知应用到目标对象后创建的对象(代理目标通知),请注意只有代理对象才有AOP功能而AOP的代码是写在通知的方法里面的如上例中的JDKProxy切入点(Pointcut) 多个连接点的集合定义了通知应该应用到那些连接点。也将Pointcut理解成一个条件 此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序适配器(Advisor) 适配器通知(Advice)切入点(Pointcut)
AOP运行原理目标对象只负责业务逻辑通知只负责AOP增强逻辑如日志数据验证等而代理对象则将业务逻辑而AOP增强代码组织起来组织者
2.2 AOP带来的好处
AOP是公用的框架代码放置的理想地方将公共代码与业务代码分离使我们在处理业务时可以专心的处理业务。 伪代码
public void doSameBusiness (long lParam,String sParam){// 记录日志log.info(调用 doSameBusiness方法参数是lParam);// 输入合法性验证if (lParam0){throws new IllegalArgumentException(xx应该大于0);}if (sParamnull || sParam.trim().equals()){throws new IllegalArgumentException(xx不能为空);}// 异常处理try{ 真正的业务处理}catch(...){}catch(...){}// 事务控制tx.commit();}通过使用AOP我们可以将日志记录数据合法性验证异常处理等功能放入AOP中那么在编写业务时就可以专心实现真正的业务逻辑代码。
3. Spring AOP
在spring中org.springframework.aop.framework.ProxyFactoryBean用来创建代理对象在一般情况下它需要注入一下三个属性
proxyInterfaces 代理应该实现的接口列表(List)interceptorNames 需要应用到目标对象上的通知Bean的名字target 目标对象 (Object)
准备工作创建一个IBookService接口及其实现类用于演示spring AOP开发示例
public interface IBookService {// 购书public boolean buy(String userName, String bookName, Double price);// 发表书评public void comment(String userName, String comments);}public class BookServiceImpl implements IBookService {private Logger logger LoggerFactory.getLogger(this.getClass());public BookServiceImpl() {super();}public boolean buy(String userName, String bookName, Double price) {//logger.info(userName{},bookName{},price{}, userName, bookName, price);// 通过控制台的输出方式模拟购书logger.info(userName buy bookName , spend price);return true;}public void comment(String userName, String comments) {logger.info(userName say: comments);}}将service配置到spring配置文件中以便于被spring管理按自己的实际情况配置
!-- 目标 --bean idbookServiceTarget classcom.zking.sp02.impl.BookServiceImpl/3.1 前置通知
前置通知需要实现org.springframework.aop.MethodBeforeAdvice前置通知将在目标对象调用前调用。示例实现购书系统AOP方式实现日志简单打印调用的方法及参数
1首先实现一个前置通知类实现接口MethodBeforeAdvice并实现接口中的before方法
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {private Logger logger LoggerFactory.getLogger(this.getClass());Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {String s [前置通知]: this.getClass() . method.getName() 将被调用参数为: Arrays.toString(args);logger.info(s);}}2将实现的前置通知配置到Spring.xml中一遍与被spring管理。需要根据自己的实际情况配置。
bean idmyMethodBeforeAdvice classcom.zking.springdemo.aop.MyMethodBeforeAdvice/3现在需要解决如何将通知和目标联系起来需要一个组织者 - 代理
bean idbookService classorg.springframework.aop.framework.ProxyFactoryBean!-- 配置代理目标 --property nametarget refbookServiceTarget/!-- 配置拦截器列表拦截器就是通知 --property nameinterceptorNameslistvaluemyMethodBeforeAdvice/value/list/property!-- 代理要实现的接口代理类与被代理类需要实现相同接口 --property nameproxyInterfaceslistvaluecom.zking.springdemo.aop.IBookService/value/list/property/bean写一个测试类测试前置通知
public class Demo {public static void main(String[] args) {ApplicationContext ucxt/u new ClassPathXmlApplicationContext(/spring.xml);IBookService bookService (IBookService)cxt.getBean(bookService);System.out.println(bookService.getClass().getName()); bookService.buy(zs, hlm, 10D);}}3.2 后置通知
在连接点正常完成后执行的通知。定义的后置通知类需要实org.springframework.aop.AfterReturningAdvice
示例:在线购书系统中要求不修改BookServiceImpl代码的情况下增加如下功能对买书的用户进行返利每买本书返利10元简单打印类似于“[后置通知] 返利10元”即可。开发步骤与前置通知类似
1 编写一个后置通知实现类
public class MyAfterReturnAdvice implements AfterReturningAdvice {private Logger logger LoggerFactory.getLogger(this.getClass());Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { logger.info([后置通知]: 返利10元); }
}2 将后置通知实现类配置到spring配置文件中以便于spring管理
bean idmyAfterReturnAdvice classcom.zking.springdemo.aop.MyAfterReturnAdvice/3解决如何将通知和目标联系起来在实现前置通知时已经配置了代理对象现在只要将后置通知也配置到拦截器列表当中即可。
!-- 配置拦截器列表拦截器就是通知 --
property nameinterceptorNameslist!-- 前置通知 --valuemyMethodBeforeAdvice/value!-- 后置通知 --valuemyAfterReturnAdvice/value/list
/property运行上例已经实现的测试类查看后置通知的运行效果。
3.3 环绕通知
包围一个连接点的通知最大特点是可以修改返回值由于它在方法前后都加入了自己的逻辑代码因此功能很强大。自定义的环绕通知需要实现org.aopalliance.intercept.MethodInterceptor接口。示例在环绕通知中输出日志和返回值
1实现一个环绕通知该类要实现MethodInterceptor接口
public class MyMethodInterceptor implements MethodInterceptor {private Logger logger LoggerFactory.getLogger(this.getClass());Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {//获取目标对象Object target invocation.getThis();//获取参数Object[] args invocation.getArguments();//获取方法Method method invocation.getMethod();logger.info([环绕通知] 前将调用{}.{}方法参数为{},target.getClass(),method.getName(), Arrays.toString(args));//调用目标对象上的方法 Object val invocation.proceed();logger.info([环绕通知] 后已调用{}.{}, 返回值{}, target.getClass(),method.getName(), val);return val;}}2在spring的配置文件中配置环绕通知以便于spring管理
bean idmyMethodInterceptor classcom.zking.springdemo.aop.MyMethodInterceptor/3解决如何将通知和目标联系起来在实现前置通知时已经配置了代理对象现在只要将环绕通知也配置到拦截器列表当中即可。
!-- 配置拦截器列表拦截器就是通知 --
property nameinterceptorNameslist!--前置通知--valuemyMethodBeforeAdvice/value!--后置通知--valuemyAfterReturnAdvice/value!--环绕通知--valuemyMethodInterceptor/value/list
/property运行上例已经实现的测试类查看后置通知的运行效果。
3.4 异常通知
异常通知需要实现ThrowsAdvice接口这个通知会在方法抛出异常退出时执行与以上演示的前置、后置、环绕通知不同主要有一下特点
这个接口里面没有定义方法要求我们的类必须实现afterThrows这个方法以异常类型作为参数无返回值
示例 1定义一个自定义异常继承RuntimeException运行时异常
public class PriceException extends RuntimeException {public PriceException() {super();}public PriceException(String message, Throwable cause) {super(message, cause);}public PriceException(String message) {super(message);}public PriceException(Throwable cause) {super(cause);}
}2创建异常通知类该类实现ThrowsAdvice接口并实现afterThrowing方法
public class MyThrowsAdvice implements ThrowsAdvice {private Logger logger LoggerFactory.getLogger(this.getClass());//以异常类型作为参数无返回值public void afterThrowing(PriceException e) {logger.info(程序发生了PriceException异常);}}剩下的步骤是将异常通知配置到spring配置文件中及在代理配置中加入异常通知的配置可参考上面的环绕通知等示例。
3.5 适配器
适配器, 通过正则表达式来定义方法切入点也就是说定义哪些方法将被拦截器处理。适配器通知(Advice)切入点(Pointcut)。 在配置适配器时需要使用org.springframework.aop.support.RegexpMethodPointcutAdvisor
配置适配器示例
!-- 配置适配器 --
bean idmyAdisor classorg.springframework.aop.support.RegexpMethodPointcutAdvisor!-- 定义正则表达式定义需要拦截的方法名 本例定义了所有以buy结尾的方法 --property namepatternslistvalue.*buy/value/list/property!-- 定义由那个通知(或者叫拦截器)来处理匹配的方法 --property nameadviceref beanmyAfterReturnAdvice//property
/bean在代理中使用刚刚配置的适配器
!-- 将直接使用后置拦截器 改为使用适配器 --
!-- valuemyMethodAfterReturnAdvice/value --!-- 通过适配器使用后置拦截器 --
valuemyAdisor/value修改代理中的拦截器列表spring配置文件代理部分将配置器直接配置在拦截器列表中即可。