spring-AOP(面向切面编程)-xml方式配置
2018-10-24 08:45:01来源:博客园 阅读 ()
AOP是针对面向对象编程的一种补充,有时使用面向对象不能很好完成一些额外的功能业务时,可以采用AOP来进行补充。
AOP术语:
-
切面(Aspect)
切面是用于编写切面逻辑的一个类,这个类很类似于JDK动态代理中的回调处理器或者cglib中的方法拦截器,主要就是将需要增强目标对象的功能代码编写在这个类中,而这些功能增强的代码就是切面逻辑。
-
切入点(Pointcut)
通常切入点都是以一种表达式的形式来描述
-
通知/增强(Advice)
通知就是切面中具体的增强逻辑,总共分为五种:
1)前置通知(在目标方法调用之前执行)
2)后置通知(在目标方法正确返回之后执行)
3)环绕通知(在目标方法调用前后执行)
4)异常通知(当目标方法抛出异常时执行,并且不会执行后置通知)
5)最终通知(不管目标方法有无异常都会执行)
-
连接点(Joinpoint)
目标对象的方法就称之为连接点,一个切入点可以对应目标对象的的多个连接点。
-
代理(Proxy)
在运行时动态创建的对象,称之为代理对象,负责调用目标对象的方法,并执行增强功能
-
目标(Target)
被代理的对象就是目标对象
-
织入(Weaver)
将切面中的通知应用到目标对象上并且产生代理的过程称之为织入。
因此通常描述为“将通知织入到具体的目标”。
项目结构:
代码示例:
applicationContext.xml配置:
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 装备UserServiceImpl --> <bean id="userService" class="edu.nf.ch11.service.impl.UserServiceImpl"/> <!-- 装配自定义的切面--> <bean id="userServiceAspect" class="edu.nf.ch11.service.aspect.UserServiceAspect"/> <!-- 配置AOP, proxy-target-class用于设置是否强制使用cglib进行动态代理 true表示强制使用,false则表示spring会根据目标对象有无实现接口来决定 使用jdk动态代理还是cglib代理。默认值就是false--> <aop:config> <!-- 配置切入点,id属性给切入点定义一个唯一标识,expression用于编写切入点表达式--> <!-- execution表达式的使用:切入范围是在方法级别--> <!-- 表达式语法[访问修饰符] 返回值类型 [完整类名].方法名(参数)--> <!-- *号表示通配所有,方法的参数可以使用".."来代表任意个数和类型的参数--> <aop:pointcut id="myCut" expression="execution(* edu.nf.ch11.service.*.*(..))"/> <!-- within表达式的使用:切入范围是在类级别--> <!--<aop:pointcut id="myCut" expression="within(edu.nf.ch11.service.impl.*)"/>--> <!-- 引用上面装配的切面类的id --> <aop:aspect ref="userServiceAspect"> <!-- 配置具体的通知方法,method指定通知的方法名 pointcut-ref引用上面定的切入点的id,也可以通过pointcut来编写相应的切入点表达式 --> <!-- 前置通知 --> <aop:before method="before" pointcut-ref="myCut"/> <!-- 环绕通知--> <aop:around method="around" pointcut-ref="myCut"/> <!-- 后置通知,returning指定后置通知的参数名,用于获取目标方法的返回值--> <aop:after-returning method="afterReturn" pointcut-ref="myCut" returning="returnVal"/> <!-- 异常通知,如果要获取目标方法抛出的异常对象,需要指定throwing属性,value对应异常通知的参数名--> <aop:after-throwing method="throwAdvice" pointcut-ref="myCut" throwing="e"/> <!-- 最终通知--> <aop:after method="after" pointcut-ref="myCut"/> </aop:aspect> </aop:config> </beans>
切面(增强)类:
package edu.nf.ch11.service.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.reflect.MethodSignature; import javax.xml.crypto.dsig.SignatureMethod; /** * @author wangl * @date 2018/10/23 * 编写一个UserService的切面 * 在切面中编写的方法都称之为通知或者是增强 * 在AOP当中,通知有五种类型 * 1. 前置通知 * 2. 后置通知 * 3. 环绕通知 * 4. 最终通知 * 5. 异常通知 * 在一个切面中,任何一种类型的通知都可以定义多个,当有多个通知存在的时候 * 就会形成一个通知栈 */ public class UserServiceAspect { /** * 前置通知 * 在执行目标方法之前执行,拦截目标方法的参数 * 可以通过JoinPoint获得目标方法的参数信息 */ public void before(JoinPoint joinPoint){ System.out.println("前置通知..."); //通过连接点获得目标对象 //joinPoint.getTarget(); //获取目标方法的参数信息 Object[] params = joinPoint.getArgs(); for (Object param : params) { System.out.println(param); } } /** * 后置通知 * 在目标方法执行完并且return之后执行 */ public void afterReturn(String returnVal){ System.out.println("后置通知..."+returnVal); } /** * 环绕通知 * @param pjp 连接点处理器,由它负责调用目标对象的具体方法 * */ public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕通知前..."); //调用目标对象的方法 Object returnVal = pjp.proceed(); //获取目标方法的参数 System.out.println(pjp.getArgs()[0]); //通过MethodSignature获取连接点方法信息 MethodSignature ms = (MethodSignature)pjp.getSignature(); //获取正在调用的目标方法 System.out.println(ms.getMethod().getName()); //获取目标方法的返回类型 System.out.println(ms.getReturnType()); System.out.println("环绕通知后..."); return returnVal; } /** * 异常通知 * @param e 获取目标方法抛出的异常对象 */ public void throwAdvice(Throwable e){ System.out.println("异常通知..."+e.getMessage()); } /** * 最终通知 */ public void after(){ System.out.println("最终通知..."); } }
UserService接口:
package edu.nf.ch11.service; /** * @author wangl * @date 2018/10/23 */ public interface UserService { /** * 添加用户 */ void addUser(); /** * 删除用户 * @param uid */ void deleteUser(String uid); /** * 查询用户 * @param uid * @return */ String getUserNameById(String uid); }
UserServiceImpl实现类:
package edu.nf.ch11.service.impl; import edu.nf.ch11.service.UserService; /** * @author wangl * @date 2018/10/23 * 目标对象(被代理的对象) * Spring的AOP中需要代理的所有目标对象都应该归纳在ioc容器中管理 */ public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("保存用户信息"); } @Override public void deleteUser(String uid) { System.out.println("删除用户,ID:" + uid); } @Override public String getUserNameById(String uid) { System.out.println("根据ID查询用户名"); //System.out.println(10/0); return "user1"; } }
程序测试类:
package edu.nf.ch11.test; import edu.nf.ch11.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author wangl * @date 2018/10/23 */ public class UserServiceAspectTest { @Test public void testAddUser(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //这里从容器中获取的对象是一个代理对象 UserService service = context.getBean("userService", UserService.class); //service.addUser(); //System.out.println("----------------------"); //service.deleteUser("10001"); //System.out.println("----------------------"); service.getUserNameById("10001"); } }
运行结果
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:为什么要使用线程池?
- 面对对象(2) 2020-05-28
- Java笔记:Java面向对象 2020-05-17
- Java面向对象 2020-05-13
- 面向对象的三大特性 2020-05-13
- Java三大特性 2020-05-13
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash