Spring的核心思想的IOC和AOP。最近学习AOP,对切面的学习有了进一步的认识。
Spring用代理类包裹切面,把他们织入到Spring管理的bean中。也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成调用伪装类,伪装类中就先执行了切面,再把调用转发给真正的目标bean。这样可以实现对业务代码的最小化侵入。使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性。Spring中日志记录,性能统计,安全控制,事务处理等都是通过AOP来管理的。
伪装类的实现有两种方式:1.实现和目标类相同的接口。这种兄弟模式下,spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把对这些接口的任何调用都转发到目标类。
2.生成子类调用,用子类来做为伪装类。这种父子模式下,spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知,并且把对这个子类的调用委托到目标类。
相比之下,还是兄弟模式好些,能更好的实现松耦合,尤其在今天都高喊着面向接口编程的情况下,父子模式只是在没有实现接口的时候,也能织入通知,应当做一种例外。
下面看一个AOP的小应用。目的是为了在addStudent方法执行前后通过AOP来进行相关操作。
在上下文中配置aspectJ。
<aop:aspectj-autoproxy/> //定义切面,切点。也可以通过注解来实现切面的和切点标识。 <aop:config> <aop:aspect id="StudentServiceAspect" ref="studentServiceAspect"> <aop:pointcut id="businessService" expression="execution(* com.lufax.test.commen.studentService.*.*(..))"/> <aop:before method="doBefore" pointcut-ref="businessService"/> <aop:after method="doAfter" pointcut-ref="businessService"/> <aop:around method="doAround" pointcut-ref="businessService"/> </aop:aspect> </aop:config>
下面定义studentService的接口。
public interface StudentService { public void addStudent(String name); }
studentService的实现类如下。
public class StudentServiceImp implements StudentService { public void addStudent(String name){ System.out.println("----正在添加" + name+"----"); } }
以上接口和实现都是正常的业务逻辑。下面写切面。
public class StudentServiceAspect { //在业务代码执行前运行 public void doBefore(){ System.out.println("类名:"); System.out.println("doBefore:开始添加学生"); }
//业务代码执行后运行 public void doAfter(JoinPoint jp){ System.out.println("doAfter:添加完毕");
//可以通过Joinpoint类来实现日志的打印。记录切点下类和方法名、参数,以便后续快速定位问题所在。 System.out.println("[类名+"+jp.getTarget().getClass().getName()+"],"+ "[方法名:"+jp.getSignature().getName()+"],"+ "[参数:"+jp.getArgs()[0]+"]"); }
//环绕通知,retVal是返回值。这里为null public Object doAround(ProceedingJoinPoint pjp)throws Throwable{ System.out.println("doAround:加入前"); Object retVal= pjp.proceed(); System.out.println(retVal); System.out.println("doAround:加入后"); return retVal; } }
通过注解实现。
@Aspect public class StudentServiceAspect { @Before(value="execution(* com.lufax.test.commen.studentService.*.addStudent(..)) ") public void doBefore(){ System.out.println("类名:"); System.out.println("doBefore:开始添加学生"); } @After(value="execution(* com.lufax.test.commen.studentService.*.addStudent(..))") public void doAfter(JoinPoint jp){ System.out.println("doAfter:添加完毕"); System.out.println("[类名+"+jp.getTarget().getClass().getName()+"],"+ "[方法名:"+jp.getSignature().getName()+"],"+ "[参数:"+jp.getArgs()[0]+"]"); } @Around(value="execution(* com.lufax.test.commen.studentService.*.addStudent(..))") public Object doAround(ProceedingJoinPoint pjp)throws Throwable{ System.out.println("doAround:加入前"); Object retVal= pjp.proceed(); System.out.println(retVal); System.out.println("doAround:加入后"); return retVal; } }
最后写测试类。
@Test public void test_AopAspectJ() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","dataSource.xml"); StudentService studentService = (StudentService) applicationContext.getBean("studentService"); studentService.addStudent("张三"); }
运行结果如下:
类名: doBefore:开始添加学生 doAround:加入前 ----正在添加张三---- doAfter:添加完毕 [类名+com.lufax.test.commen.studentService.StudentServiceImp],[方法名:addStudent],[参数:张三] null doAround:加入后