• 1. AOP
  • 2. 目标理解什么是AOP Spring中的AOP
  • 3. 什么是AOPAspect-oriented programming 面向切面编程 AOP并不会取代OOP,而是作为OOP的补充。 AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
  • 4. 记录日志在代码中无处不在先来看一个例子 为了跟踪应用程序的运行过程,很多方法都需要记录日志信息。我们一般这样写: package com.aptech.aop2; import org.apache.log4j.Logger; public class Person { private Logger logger = Logger.getLogger(Person.class); public void sleep(){ logger.info(“开始执行时间:“ + new Date()); System.out.println("睡觉中"); logger.info(“执行结束时间:” + new Date()); } public void eating(){ logger.info("开始执行时间:“ + new Date()"); System.out.println("正在吃饭中"); logger.info("“执行结束时间:” + new Date()"); } }
  • 5. 提问:弊端在哪里?混淆了业务方法本身的职责 维护工作量巨大
  • 6. 解决方案1-静态代理目地是将业务代码与日志代码完全分离,实现松散耦合. 代理对象与被代理对象必须实现同一接口,在代理对象中实现与日志记录的相关服务,并在需要的时候呼叫被代理对象,而被代理对象只保留业务代码.
  • 7. 静态代理实现接口: package com.aptech.aop2; public interface IPerson { public abstract void sleep(); public abstract void eating(); }
  • 8. 被代理类 package com.aptech.aop2; public class Person implements IPerson { public void sleep(){ System.out.println("睡觉中"); } public void eating(){ System.out.println("正在吃饭中"); } }
  • 9. 代理类 package com.aptech.aop2; import org.apache.log4j.Logger; public class PersonProxy implements IPerson { private IPerson person; private Logger logger = Logger.getLogger(PersonProxy.class); public PersonProxy(IPerson person) { this.person = person; } public void eating() { logger.info("开始执行时间:“ + new Date()");person.eating(); logger.info("“执行结束时间:” + new Date()"); } public void sleep() { logger.info("开始执行时间:“ + new Date()");person.sleep(); logger.info("“执行结束时间:” + new Date()"); } }
  • 10. 测试类 package com.aptech.aop2; public class PersonTest { public static void main(String[] args) { IPerson proxy = new PersonProxy(new Person()); proxy.eating(); proxy.sleep(); } }
  • 11. 静态代理的弊端一个代理接口只能服务于一种类型的对象.对于稍大点的项目根本无法胜任.
  • 12. 解决方案2-动态代理在JDK1.3之后加入了可协助开发的动态代理功能.不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象. 一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口. 通过InvocationHandler接口实现的动态代理只能代理接口的实现类.
  • 13. 动态代理实现处理者(Handler) package com.aptech.aop2; public class DynaProxyHandler implements InvocationHandler { private Logger logger = Logger.getLogger(DynaProxyHandler.class); private Object target;//被代理对象 public void setTarget(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { logger.info("执行开始时间:" + new Date()); Object result = method.invoke(target, args); logger.info("执行结束时间:" + new Date()); return result;//返回method执行结果 } }
  • 14. 生产代理对象的工厂 package com.aptech.aop2; import java.lang.reflect.Proxy; public class DynaProxyFactory { //obj为被代理对象 public static Object getProxy(Object obj){ DynaProxyHandler handler = new DynaProxyHandler(); handler.setTarget(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); } }
  • 15. 测试类 package com.aptech.aop2; public class PersonTest { public static void main(String[] args) { IPerson person = (IPerson) DynaProxyFactory.getProxy(new Person()); //返回代理类,代理类是JVM在内存中动态创建的,该类实现传入的接口数组 //的全部接口(的全部方法). person.eating(); person.sleep(); } }
  • 16. AOP的定义上面例子中 使用代理对象将日志记录与业务逻辑无关的动作或任务提取出来,设计为一个服务对象,这样的对象称之为aspect(切面). 服务对象(本例为日志记录)横切(Cross-cutting)入Person的程序执行流程中,这个动作叫横切关切点(Cross-cutting concern). AOP定义 将Cross-cutting concern设计为通用,不介入特定业务对象的一个职责清楚的Aspect对象,这就是Aspect-oriented programming,缩写即AOP.
  • 17. AOP中的其他观念和术语Advice (处理). Aspect的具体实现称之为Advice(处理).上例中DynaProxyHandler类就是Advice的一个具体实现. Joinpoint(连接点) Advice在应用程序中被执行的时机称为Joinpoint(连接点),这个时机可能是某个方法被执行之前或之后(或两者都有). Pointcut(切入点) 一种行为方式,用于指定哪些Aspect在哪些Joinpoint中织入到应用程序之上. Target(目标对象) 一个Advice被应用的目标对象. Weave(织入) Advice被应用至目标对象之上的过程称这为织入(Weave)
  • 18. 术语图解
  • 19. 最重要的三个概念 advice,pointcut和 advisor advice是你想向别的程序内部不同的地方注入的代码。 pointcut定义了需要注入advice的位置,通常是某个特定的类的一个 public方法。 advisor是pointcut和advice的装配器,是将advice注入主程序中预定义位置的代码。
  • 20. Spring AOPSpring中,Target必须实现预先定义好的接口,这样才会使用Proxy进行动态代理. Spring只支持方法的Joinpoint,也就是Advice将在方法执行的前后被应用.
  • 21. AdviceAdvice包括Aspect的真正逻辑,在Java中具体来说就是一个类. Spring中的Advice包括: org.springframework.aop. MethodBeforeAdvice org.springframework.aop. AfterReturningAdvice org.aopalliance.intercept.MethodInterceptor org.springframework.aop.ThrowsAdvice
  • 22. MethodBeforeAdviceMethodBeforeAdvice在目标对象的方法执行之前被呼叫. 通过实现org.springframework.aop. MethodBeforeAdvice接口来实现业务逻辑. 示例:
  • 23. package com.aptech.aop3; import java.lang.reflect.Method; import java.util.Date; import org.apache.log4j.Logger; import org.springframework.aop.MethodBeforeAdvice; public class BeforeAdvice implements MethodBeforeAdvice { private Logger logger = Logger.getLogger(this.getClass()); public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("方法:" + method); System.out.println("目标对象:" + target); logger.info("在目标方法开始执行之前的时间:" + new Date()); } }
  • 24. 目标接口 public interface IBank { public int getMoney(int howmany); public void setMoney(int howmany); } 类 public class Bank implements IBank{ public int getMoney(int howmany) { System.out.println("取了" + howmany); return howmany; } public void setMoney(int howmany) { System.out.println("存了" + howmany); } }
  • 25. 配置 class="org.springframework.aop.framework.ProxyFactoryBean"> com.aptech.aop3.IBank before
  • 26. 测试类: package com.aptech.aop3; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext ac = new FileSystemXmlApplicationContext(new String[]{"src/applicationContext.xml", "src/newxml.xml"}); IBank bank = (IBank) ac.getBean(“beforeProxy”);//这里的参数是代理工厂的ID bank.setMoney(1000); bank.getMoney(1000); } }
  • 27. AfterReturningAdviceAfterReturningAdvice在目标方法执行之后被执行. 通过org.springframework.aop. AfterReturningAdvice 接口来实现业务逻辑. 示例:
  • 28. package com.aptech.aop3; import java.lang.reflect.Method; import java.util.Date; import org.apache.log4j.Logger; import org.springframework.aop.AfterReturningAdvice; public class AfterAdvice implements AfterReturningAdvice { private Logger logger = Logger.getLogger(this.getClass()); public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("目标方法的返回值:" + returnValue); System.out.println("目标方法的名称:" + method); System.out.println("目标对象:" + target); logger.info("目标方法执行后的时间:" + new Date()); } }
  • 29. 目标接口及类同上.配置如下: com.aptech.aop3.IBank before after
  • 30. MethodInterceptor如果要在目标方法执行前后都介入Advice服务逻辑,则通过实现org.aopalliance.intercept.MethodInterceptor接口来实现. 示例.
  • 31. package com.aptech.aop3; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.log4j.Logger; public class AroundAdvice implements MethodInterceptor { private Logger logger = Logger.getLogger(this.getClass()); public Object invoke(MethodInvocation methodInvocation) throws Throwable { logger.info("目标方法之前执行"); Object result = methodInvocation.proceed();//执行目标方法 logger.info("目标方法之后执行"); return result; } }
  • 32. 目标接口及类同上.配置如下: com.aptech.aop3.IBank around
  • 33. 细化Advice织入的时机前面的Advice在目标对象的任何方法执行时都会被织入,事实上可以更加细化Advice织入的时机. 通过下列两个类来实现 org.springframework.aop.support.NameMatchMethodPointcutAdvisor org.springframework.aop.support.RegexpMethodPointcutAdvisor
  • 34. NameMatchMethodPointcutAdvisor该类的setMappedName和setMappedNames方法用于设定执行哪些方法时织入指定Advice. 可以使用*来进行模糊匹配. 比如:只在执行getMoney()方法时才织入MethodBeforeAdvice 只需要配置即可,无须写代码.
  • 35. getMoney
  • 36. com.aptech.aop3.IBank namematch
  • 37. RegexpMethodPointcutAdvisor通过”正则表达式”来指定要在哪些方法执行时织入Advice.通过pattern来限定. 可用的符号:符号描述.符合任何单一字符+符合前一个字符一次或多次*符合前一个字符0次或多次\转义
  • 38. 示例:只在执行带e的方法时才织入MethodBeforeAdvice: .*e.*
  • 39. com.aptech.aop3.IBank regexp
  • 40. 自动代理自动代理可以让您不用为每一个目标对象手动定义代理对象,而是自动为符合条件的目标对象建立代理对象. 有两种实现方法: org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator 类 org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator 类
  • 41. BeanNameAutoProxyCreator可以为目标对象取好适当的Bean名称,例如为某些服务对象取名为xxxService,这么一来,就可以使用BeanNameAutoProxyCreator类来为这些Bean设定自动代理. 示例:代理*Service的Bean
  • 42. *Service around
  • 43. 代理下面的Bean 测试: ApplicationContext ac = ….. IBank bank = (IBank) ac.getBean("bankService"); 因为是自动代理,所以spring容器会根据Bean名字自动搜寻要代理的目标对象,并将around织入目标对象的方法中.
  • 44. 总结AOP的概念 相关术语 动态代理 前置通知 返回后通知 环绕通知 抛出后通知 细化目标对象的哪些方法织入Advice 自动代理