连接点(JoinPoint) ,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。
方式一:xml方式配置
1.配置xml文件
<bean id="dataSourceExchange" class="com.ooper.www.datasource.DataSourceExchange"/> <!--辅助功能bean--> <aop:config> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.ooper.www.service.Impl.AccountServiceImpl.*(..))"/> <!-- 指定核心业务功能 --> <aop:aspect ref="dataSourceExchange"> <!--指定辅助功能 --> <aop:before pointcut-ref="dataSourcePointcut" method="before"/><!-- 执行核心任务之前执行 --> <aop:after pointcut-ref="dataSourcePointcut" method="after"/><!-- 执行核心任务之后执行 --> </aop:aspect> </aop:config>
2. 辅助功能java代码
package com.ooper.www.datasource; import org.aspectj.lang.JoinPoint; public class DataSourceExchange { public void before(JoinPoint point) { //获取目标对象的类类型 Class<?> aClass = point.getTarget().getClass(); String c = aClass.getName(); String[] ss = c.split("\\."); //获取包名用于区分不同数据源 String methodName = ss[5]; if ("AccountServiceImpl".equals(methodName)) { DataSourceHolder.setDbType(DataSourceEnum.DS2.getKey()); System.out.println("数据源:"+DataSourceEnum.DS2.getKey()); } else { DataSourceHolder.setDbType(DataSourceEnum.DS1.getKey()); System.out.println("数据源:"+DataSourceEnum.DS1.getKey()); } } /** * 执行后将数据源置为空 */ public void after(JoinPoint point) { System.out.println("point:" + point); DataSourceHolder.setDbType(null); } }
方式二:注解方式
1.xml配置文件
<!-- 注解方式实现AOP --> <!-- 激活自动代理功能 --> <!-- 代理方式1:采用JDK代理 --> <aop:aspectj-autoproxy/> <!-- 代理方式2:cglib代理 --> <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> --> <!-- 找到被注解了的切面类,进行切面配置 --> <context:component-scan base-package="com.how2java.aspect"/> <context:component-scan base-package="com.how2java.controller"/>
2.注解配置切面代码
package com.how2java.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /**spring AOP 此段小代码演示了spring aop中@Around @Before @After三个注解的区别 * @Before是在所拦截方法执行之前执行一段逻辑。@After 是在所拦截方法执行之后执行一段逻辑。@Around是可以同时在所拦截方法的前后执行一段逻辑。 * @author Administrator * 通过aop拦截后执行具体操作 */ @Aspect @Component public class LogIntercept { // @Pointcut("execution(* com.how2java.controller..*.*(..))") public void recordLog(){} @Before("execution(* com.how2java.controller..*.*(..))") // @Before("recordLog()") public void before() { this.printLog("已经记录下操作日志@Before 方法执行前"); } @Around("execution(* com.how2java.controller..*.*(..))") // @Around("recordLog()") public Object around(ProceedingJoinPoint pjp) throws Throwable{ this.printLog("已经记录下操作日志@Around 方法执行前"); Object obj = pjp.proceed(); this.printLog("已经记录下操作日志@Around 方法执行后"); return obj; } @After("execution(* com.how2java.controller..*.*(..))") // @After("recordLog()") public void after() { this.printLog("已经记录下操作日志@After 方法执行后"); } private void printLog(String str){ System.out.println(str); } }
package com.how2java.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect // 注解表示这是一个切面 @Component //表示这是一个bean,由Spring进行管理,使用注解时一定要使用@component或者@Repository、@Controller、@Service中一个去声明,将切面类放入到spring容器中,不然就去xml中显式写一个bean,不然的话就会报错,无法实现切面功能。 public class LoggerAspect { @Around(value = "execution(* com.how2java.controller..*.*(..))") //表示对com.how2java.controller 这个包中的所有方法进行切面操作 /* AOP(execution表达式) * * execution(* com.how2java.controller..*.*(..)) 解释如下: 符号 含义 execution() 表达式的主体; 第一个”*“符号 表示返回值的类型任意; com.how2java.controller AOP所切的服务的包名,即,我们的业务部分 包名后面的”..“ 表示当前包及子包 第二个”*“ 表示类名,*即所有类。此处可以自定义,下文有举例 .*(..) 表示任何方法名,括号表示参数,两个点表示任何参数类型 */ public Object log(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("start log:" + joinPoint.getSignature().getName()); Object object = joinPoint.proceed();//就是将来与某个核心功能编织之后,用于执行核心功能的代码 System.out.println("end log:" + joinPoint.getSignature().getName()); return object; } }