Java web 环境搭建
Java web 项目搭建
Java Spring IOC用法
spring提供了两个核心功能,一个是IoC(控制反转),另一个即是Aop(面向切面编程),IoC有助于应用对象之间的解耦,AOP则能够实现横切关注点(如日志、安全、缓存和事务管理)与他们所影响的对象之间的解耦。html
AOP主要包含了通知、切点和链接点等术语,介绍以下java
通知(Advice)
通知定义了切面是什么以及什么时候调用,什么时候调用包含如下几种web
Before 在方法被调用以前调用通知
After 在方法完成以后调用通知,不管方法执行是否成功
After-returning 在方法成功执行以后调用通知
After-throwing 在方法抛出异常后调用通知
Around 通知包裹了被通知的方法,在被通知的方法调用以前和调用以后执行自定义的行为正则表达式
切点(PointCut)
通知定义了切面的什么和什么时候,切点定义了何处,切点的定义会匹配通知所要织入的一个或多个链接点,咱们一般使用明确的类的方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称来指定这些切点。
切点的格式以下spring
execution(* com.ganji.demo.service.user.UserService.GetDemoUser (..) )
express
链接点(JoinPoint)
链接点是在应用执行过程当中可以插入切面的一个点,这个点能够是调用方法时,抛出异常时,甚至是修改一个字段时,切面代码能够利用这些链接点插入到应用的正常流程中,并添加新的行为,如日志、安全、事务、缓存等。编程
现阶段的AOP框架
AOP框架除了Spring AOP以外,还包括AspectJ、JBoss AOP;
上述框架的区别是Spring AOP只支持到方法链接点,另外两个还支持字段和构造器链接点。缓存
同依赖注入同样,AOP在spring中有两种配置方式,一是xml配置的方式,二是自动注解的模式。安全
在xml中,咱们使用以下AOP配置元素声明切面框架
AOP配置元素 | 描述 ------------ | ------------- `<aop:advisor>` | 定义AOP通知器 `<aop:after>` | 定义AOP后置通知(无论该方法是否执行成功) `<aop:after-returning>` | 在方法成功执行后调用通知 `<aop:after-throwing>` | 在方法抛出异常后调用通知 `<aop:around>` | 定义AOP环绕通知 `<aop:aspect>` | 定义切面 `<aop:aspect-autoproxy>` | 定义`@AspectJ`注解驱动的切面 `<aop:before>` | 定义AOP前置通知 `<aop:config>` | 顶层的AOP配置元素,大多数的<aop:*>包含在<aop:config>元素内 `<aop:declare-parent>` | 为被通知的对象引入额外的接口,并透明的实现 `<aop:pointcut>` | 定义切点
咱们在service层添加com.ganji.demo.service.aspect.XmlAopDemoUserLog
类,里面实现了拦截方法,具体以下
package com.ganji.demo.service.aspect; import org.aspectj.lang.ProceedingJoinPoint; /** * Created by admin on 2015/9/2. */ public class XmlAopDemoUserLog { // 方法执行前通知 public void beforeLog() { System.out.println("开始执行前置通知 日志记录"); } // 方法执行完后通知 public void afterLog() { System.out.println("开始执行后置通知 日志记录"); } // 执行成功后通知 public void afterReturningLog() { System.out.println("方法成功执行后通知 日志记录"); } // 抛出异常后通知 public void afterThrowingLog() { System.out.println("方法抛出异常后执行通知 日志记录"); } // 环绕通知 public Object aroundLog(ProceedingJoinPoint joinpoint) { Object result = null; try { System.out.println("环绕通知开始 日志记录"); long start = System.currentTimeMillis(); //有返回参数 则需返回值 result = joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("总共执行时长" + (end - start) + " 毫秒"); System.out.println("环绕通知结束 日志记录"); } catch (Throwable t) { System.out.println("出现错误"); } return result; } }
咱们在web层,web-inf/dispatcher-servlet.xml
中定义切面,具体以下
<!--定义切面 指定拦截方法时 作什么--> <bean id="xmlAopDemoUserLog" class="com.ganji.demo.service.aspect.XmlAopDemoUserLog"></bean> <aop:config> <aop:aspect ref="xmlAopDemoUserLog"> <!--指定切面--> <!--定义切点--> <aop:pointcut id="logpoint" expression="execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..))"></aop:pointcut> <!--定义链接点--> <aop:before pointcut-ref="logpoint" method="beforeLog"></aop:before> <aop:after pointcut-ref="logpoint" method="afterLog"></aop:after> <aop:after-returning pointcut-ref="logpoint" method="afterReturningLog"></aop:after-returning> <aop:after-throwing pointcut-ref="logpoint" method="afterThrowingLog"></aop:after-throwing> </aop:aspect> </aop:config>
在controller下调用,调用具体以下
DemoUserEntity demoUser=userService.GetDemoUser(1);
这是运行起来 咱们将看到打印出以下日志
开始执行前置通知 日志记录
开始执行后置通知 日志记录
方法成功执行后通知 日志记录
若是经过xml配置,咱们还能够实现环绕通知,环绕通知的目的是把前置通知和后置通知的信息共享起来。同时还能够为通知传递方法的参数,在切面拦截中验证参数的有效性。
在上述2.1中咱们经过xml配置的形式 实现了AOP编程,如今咱们经过不配置xml,配置注解的形式实现AOP。
使用配置注解,首先咱们要将切面在spring上下文中声明成自动代理bean,咱们须要在web层的web-inf/dispatcher-servlet.xml
文件中配置以下一句话便可
<aop:aspectj-autoproxy />
固然咱们须要在xml的根目录beans下引用aop的命名空间和xsi
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
@Aspect
注解声明一个切面,只须要在类名上添加@Aspect
属性便可,具体的链接点,咱们用@Pointcut
和@Before
、@After
等标注。具体以下
在声明前 咱们须要依赖配置pom
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.11</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.11</version> </dependency>
声明切面类,包含了注解@Aspect
以及什么时候(如@Before
)执行通知
package com.ganji.demo.service.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Service; /** * Created by admin on 2015/9/2. */ @Aspect @Service public class XmlAopDemoUserLog { // 配置切点 及要传的参数 @Pointcut("execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)") public void pointCut(int id) { } // 配置链接点 方法开始执行时通知 @Before("pointCut(id)") public void beforeLog(int id) { System.out.println("开始执行前置通知 日志记录:"+id); } // 方法执行完后通知 @After("pointCut(id)") public void afterLog(int id) { System.out.println("开始执行后置通知 日志记录:"+id); } // 执行成功后通知 @AfterReturning("pointCut(id)") public void afterReturningLog(int id) { System.out.println("方法成功执行后通知 日志记录:"+id); } // 抛出异常后通知 @AfterThrowing("pointCut(id)") public void afterThrowingLog(int id) { System.out.println("方法抛出异常后执行通知 日志记录"+id); } // 环绕通知 @Around("pointCut(id)") public Object aroundLog(ProceedingJoinPoint joinpoint,int id) { Object result = null; try { System.out.println("环绕通知开始 日志记录"+id); long start = System.currentTimeMillis(); //有返回参数 则需返回值 result = joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("总共执行时长" + (end - start) + " 毫秒"); System.out.println("环绕通知结束 日志记录"); } catch (Throwable t) { System.out.println("出现错误"); } return result; } }
按照上述两个步骤,使用注解实现Aop便可,这里依赖了IOC。