Spring AOP

1. 什么是AOP及其好处 *

Aspect Oriented Programming 面向方面编程戒面向切面编程。
AOP关注点是共同处理,可以通过配置将其作用到某一个戒多个目标对象上。好处是实现组件重复
利用,改善程序结构,提高灵活性。将共通组件不目标对象解耦。
2. AOP相关概念 *
1) Aspect切面(方面)
指的是共通业务处理,可以切入到多个目标对象,可多次使用

2) JoinPoint连接点
指的是切面组件在目标对象上作用的位置,
例如:方法上戒者发生异常。
3) Pointcut切入点
切入点是连接点的集合,采用表达式指定
4) Target Object目标对象
5) Advice通知
指的是切面组件在连接点上执行的劢作。
例如:在方法调用前、方法调用后、方法调用前后等。

6) AutoProxy劢态代理
采用了AOP乊后,容器返回的对象是代理对象。用户在使用时,由代理对象调用切面组件和
目标对象的功能。
a. 目标对象有接口采用JDK代理、
b. 目标对象没有接口采用CGLIB代理
【案例1】AOP演示 **
1) 新建工程spring2
2) 导入Jar包
AoP需要的Jar包:aspectjrt.jar和aspectjweaver.jar
劢态代理需要cglib.jar
3) 新建接口UserServie

[java][/java] view plaincopy

  1. package tarena.service;
  2. public interface UserService {
  3. public void update();
  4. public void delete();
  5. public void save();
  6. }

4) 新建实现类UserServiceImpl

[java][/java] view plaincopy

  1. package tarena.service;
  2. public class UserServiceImpl implements UserService {
  3. public void delete() {System.out.println(“删除用户信息”);}
  4. public void save() {System.out.println(“保存用户信息”);}
  5. public void update() {System.out.println(“更新用户信息”);}
  6. }

5) 新建aop.xml

[html][/html] view plaincopy

  1. <?xml version=”1.0″ encoding=”UTF-8″?>
  2. <beans xmlns=”http://www.springframework.org/schema/beans”
  3. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
  4. xmlns:context=”http://www.springframework.org/schema/context”
  5. xmlns:aop=”http://www.springframework.org/schema/aop”
  6. xsi:schemaLocation=”http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context-2.5.xsd
  10. http://www.springframework.org/schema/aop
  11. http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”>
  12. <bean id=”userserivce” class=”tarena.service.UserServiceImpl”>
  13. </bean>
  14. </beans>

6) 新建Test

[java][/java] view plaincopy

  1. package tarena.service;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. public class Test {
  5. private static final String CONFIG = “aop.xml”;
  6. /**
  7. * @param args
  8. */
  9. public static void main(String[] args) {
  10. ApplicationContext ac =
  11. new ClassPathXmlApplicationContext(CONFIG);
  12. UserService userService = (UserService)ac.getBean(“userserivce”);
  13. userService.update();
  14. userService.save();
  15.  userService.delete();
  16. }
  17. }

7) 运行Test
如上,已经将UserService纳入Spring容器的管理中。
我们现在又这样的需求,要为UserSerice的操作增加日志记录功能。
我们需要为更新、保存、删除操作增加记录日志功能,那么记录日志功能就属于切面功能。
增加AoP功能
8) 新建aop.OptLogger
在Spring中,切面组件只要是普通的bean即可。
OptLogger是记录操作日志的切面组件

[java][/java] view plaincopy

  1. package tarena.aop;
  2. /**
  3. * 切面组件,记录操作日志
  4. * @author tarena
  5. *
  6. */
  7. public class OptLogger {
  8. public void logger(){
  9. System.out.println(“记录操作日志了…”);
  10. }
  11. }

9) 修改aop.xml

将切面组件OptLogger加入到配置文件中;配置aop

[html][/html] view plaincopy

  1. <?xml version=”1.0″ encoding=”UTF-8″?>
  2. <beans xmlns=”http://www.springframework.org/schema/beans”
  3. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
  4. xmlns:context=”http://www.springframework.org/schema/context”
  5. xmlns:aop=”http://www.springframework.org/schema/aop”
  6. xsi:schemaLocation=”http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context-2.5.xsd
  10. http://www.springframework.org/schema/aop
  11. http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”>
  12. <bean id=”userserivce” class=”tarena.service.UserServiceImpl”></bean>
  13. <bean id=”optlogger” class=”tarena.aop.OptLogger”></bean>
  14. <aop:config>
  15. <aop:pointcut id=”servicepointcut”
  16. expression=”execution(* tarena.service.*.*(..))” />
  17. <aop:aspect id=”loggeraspect” ref=”optlogger”>
  18. <aop:before method=”logger” pointcut-ref=”servicepointcut”/>
  19. </aop:aspect>
  20. </aop:config>
  21. </beans>

<aop:aspect > 用于配置切面
. id属性
. ref属性 用于关联切面的bean
<aop:pointcut/>用于设置切入点
. expression属性 类似于正则形式的表达式(后期讲,先使用)
execution()用于设置方法限定
. execution(* tarena.service.*.*(..))
表示丌限定返回类型,限定指定tarena.service包下的
所有方法,丌限定参数类型
. <aop:before> 表示采用before这种通知,作用于pointcut和方法上
10) 运行Test
在操作乊前都进行了记录日志操作通知
如果这样会在操作后记录日志
11) 修改aop.xml

[html][/html] view plaincopy

  1. <bean id=”userserivce” class=”tarena.service.UserServiceImpl”></bean>
  2. <bean id=”optlogger” class=”tarena.aop.OptLogger”></bean>
  3. <aop:config>
  4. <aop:pointcut id=”servicepointcut”
  5. expression=”execution(* tarena.service.*.*(..))” />
  6. <aop:aspect id=”loggeraspect” ref=”optlogger”>
  7. <aop:before method=”logger” pointcut-ref=”servicepointcut”/>
  8. </aop:aspect>
  9. </aop:config>
  10. </beans>

12) 运行Test
我们如果想将操作的内容在日志中做一些记录,该怎么做?
13) 修改aop.xml

[html][/html] view plaincopy

  1. <bean id=”userserivce” class=”tarena.service.UserServiceImpl”></bean>
  2. <bean id=”optlogger” class=”tarena.aop.OptLogger”></bean>
  3. <aop:config>
  4. <aop:pointcut id=”servicepointcut”
  5. expression=”execution(* tarena.service.*.*(..))” />
  6. <aop:aspect id=”loggeraspect” ref=”optlogger”>
  7. <aop:around method=”logger” pointcut-ref=”servicepointcut”/>
  8. </aop:aspect>
  9. </aop:config>
  10. </beans>

14) 修改OptLogger
当aop.xml中设置为<aop:around>通知形式后,我们可以通过ProceedingJoinPoint对象(连
接点)来获取方法名、类名等。

[java][/java] view plaincopy

  1. package tarena.aop;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. /**
  4. * 切面组件,记录操作日志
  5.  * @author tarena
  6. *
  7. */
  8. public class OptLogger {
  9. public Object logger(ProceedingJoinPoint pjp) throws Throwable{
  10. //proceed()方法有执行目标对象的功能
  11. Object obj = pjp.proceed();
  12. //获取方法名
  13. String method =
  14. pjp.getSignature().getName();
  15. //获取目标对象类名
  16. String clazzName =
  17. pjp.getTarget().getClass().getName();
  18. System.out.println(
  19. “执行了” + clazzName + “的” + method + “方法”);
  20. return obj;
  21. }
  22. }

15) 运行Test
我们可以做的更用户友好些
16) 新建opt.properties

内容是更友好的一些文字描述
tarena.service.UserServiceImpl.update=\u7528\u6237\u66f4\u65b0\u64cd\u4f5c
tarena.service.UserServiceImpl.save=\u7528\u6237\u4fdd\u5b58\u64cd\u4f5c
tarena.service.UserServiceImpl.delete=\u7528\u6237\u5220\u9664\u64cd\u4f5c
17) 新建PropertiesUtil

[java][/java] view plaincopy

  1. package tarena.util;
  2. import java.io.IOException;
  3. import java.util.Properties;
  4. public class PropertiesUtil {
  5. static Properties props = new Properties();
  6. private PropertiesUtil(){}
  7. public static Properties getInstance(String path)
  8. throws IOException{
  9. props.load(
  10. PropertiesUtil.class.getClassLoader()  .getResourceAsStream(path));
  11. return props;
  12. }
  13. public static String getProperty(String key){
  14. String val = “”;
  15. if(props != null){
  16. String prop = props.getProperty(key);
  17. if(prop != null){
  18. val = prop;
  19. }
  20. }
  21. return val;
  22. }
  23. }

18) 修改OptLogger

[java][/java] view plaincopy

  1. package tarena.aop;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import tarena.util.PropertiesUtil;
  4. /**
  5. * 切面组件,记录操作日志
  6. * @author tarena
  7. *
  8. */
  9. public class OptLogger {
  10. public Object logger(ProceedingJoinPoint pjp)
  11. throws Throwable{
  12. Object obj = pjp.proceed();//执行目标对象的功能
  13. String methodName = pjp.getSignature().getName();
  14. String clazzName = pjp.getTarget().getClass().getName();
  15. PropertiesUtil.getInstance(“tarena/opt.properties”);
  16.  String key = clazzName+”.”+methodName;
  17. System.out.println(
  18. “执行了”+PropertiesUtil.getProperty(key));
  19. return obj;
  20. }
  21. }

19) 运行Test

如上案例,我们可以了解到IoC是解决两个对象乊间的关系,AOP是解决一个对象和某一批
对象乊间的关系。

标签