spring -- Spring笔记5 AOP
Spring笔记5 AOP
2016年1月29日
9:37
aop是什么:面向切面的编程(OOP是面向对象的编程)
为什么要用aop:如果我们要写一个简单的计算器,核心的代码只有加减乘除四个方法,但是如果我们还想要有一些日志来提示使用者,这些提示对每个方法来说都是相近的,如果我们在每个方法里面都加上提示输出,就会让代码显得很冗余,而且不利于后期的更新和维护,而这种情况下我们就可以使用aop。
首先我们用代理类的方法来实现这一功能:
CountIplm.java文件实现了Count.java接口(Iplm应该是Ipml,后来发现了不想改了)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package com.firefly.spring.count; public class CountIplmimplements Count { public int add(inti, int j) { int result = i + j; return result; } public int sub(inti, int j) { int result = i - j; return result; } public int mul(inti, int j) { int result = i * j; return result; } public int div(inti, int j) { int result = i / j; return result; } } |
代理类CountLoggingProxy.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package com.firefly.spring.count; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class CountLogginProxy { //要代理的对象 private Count target; public CountLogginProxy(Count target2) { this.target = target2; } public Count getLoggingProxy(){ Count proxy = null; //代理对象由哪一个类加载器负责加载 ClassLoader loader = target.getClass().getClassLoader(); //代理对象的类型。即其中有哪些方法 Class [] interfaces = new Class[]{Count.class}; //当调用代理对象其中的方法时,该执行的代码 InvocationHandler h = new InvocationHandler() { //正在返回的对象 //method正在被调用的方法 //arg2调用方法时传入的参数 public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable { StringmethodName = arg1.getName(); System.out.println(“The method “+methodName+” begins with”+Arrays.asList(arg2)); Objectresult = arg1.invoke(target, arg2); returnresult; } }; proxy = (Count)Proxy.newProxyInstance(loader, interfaces, h); return proxy; } } |
调用类Main.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.firefly.spring.count; public class Main { public static voidmain(String[] args) { Count target =new CountIplm(); Count proxy = new CountLogginProxy(target).getLoggingProxy(); int result = proxy.add(1, 2); System.out.println(result); } } |
本来代理类与spring关系不大,可是java基础太烂记下来当是复习了。
aop方法实现:
aop中的一些术语:
切面:横切关注点,意会。。
通知:切面必须完成的工作,例如例子中的打印日志提示。
目标:被通知的对象,例子中4个不同的方法调用时生成的对象。
代理:向目标对象应用通知后创建的对象,可以理解为被包装后的目标形成的新对象。
连接点和切点以后详述。
CountIplm.java文件实现了Count.java接口,与上面唯一的不同是要用@Component把类加入到IOC容器中。
LoggingAspect.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.firefly.spring.aop; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; //把这个类声明为一个切面:需要把该类放到IOC容器中,再声明为一个切面 @Aspect @Component public class LoggingAspect { //指定该方法在哪些类的哪些方法前执行 @Before(“execution(public int com.firefly.spring.aop.Count.*(int,int))”) public void beforeMethod(JoinPoint joinpoint){ String methodName = joinpoint.getSignature().getName(); List<Object> args = Arrays.asList(joinpoint.getArgs()); System.out.println(“The method “+methodName+” begins with “+args); } } |
bean的配置代码:
| 1 2 3 4 5 |
<!– 自动扫描的包 –> <context:component-scan base-package=”com.firefly.spring.aop”></context:component-scan> <!– 使aspject注解起作用:自动为匹配的类生成代理对象 –> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> |
调用的方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.firefly.spring.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static voidmain(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationContext.xml”); Count count = ac.getBean(Count.class); int result = count.add(2, 3); System.out.println(result); result = count.mul(2, 3); System.out.println(result); } } |
以上例子中用到了前置通知,相应的还有后置通知,@after在目标方法执行后执行,配置与前置通知相仿。
后置通知不论方法是否发生异常它都会被执行
后置通知还不能访问执行结果。
返回通知可以访问方法的返回结果,是在方法正常执行后执行,@AfterReturning(value=“execution()”)配置
异常通知,程序出现异常时候调用,@AfterThrowing(value=“execution()”)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@After(“execution(public int com.firefly.spring.aop.Count.*(..))”) public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println(“The method “+methodName+” end”); } @AfterReturning(value=”execution(public int com.firefly.spring.aop.Count.*(..))”,returning=”result”) public void afterReturning(JoinPoint joinPoint,Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println(“The method “+methodName+” end with “+result); } @AfterThrowing(value=”execution(public int com.firefly.spring.aop.Count.*(..))”,throwing=”e”) public void afterThrowing(JoinPoint joinPoint,Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println(“The method “+methodName+” have exception “+e); } |
当有多个切面对同一个方法进行操作时,我们可以用@Order(n)来对切面设置优先级,n越小优先级越高。
| 1 2 3 |
//使用@Pointcut来声明一个切入点表达式,一般的这个方法里面不需要再写别的代码 @Pointcut(“execution(public int com.firefly.spring.aop.Count.*(..))”) public void flog(){} |
每次都去写切入点会很麻烦,所以我们把切入点写成一个表达式,用上面的方法,以后在配置的时候只要用flog就行了。
一下为用文件配置AOP的方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<bean id=”count” class=”com.firefly.spring.aop.CountIplm”></bean> <bean id=”loggingAspect” class=”com.firefly.spring.aop.LoggingAspect”></bean> <!– 配置AOP –> <aop:config> <!– 配置切点表达式 –> <aop:pointcut expression=”execution(* com.firefly.spring.aop.Count.*(..))” id=”pointcut”/> <!– 配置切面通知 –> <aop:aspect ref=”loggingAspect” order=”2”> <aop:before method=”beforeMethod” pointcut-ref=”pointcut”/> <aop:after method=”afterMethod” pointcut-ref=”pointcut”/> <aop:after-throwing method=”afterThrowing” pointcut-ref=”pointcut” throwing=”e”/> <aop:after-returning method=”afterReturning” pointcut-ref=”pointcut” returning=”result”/> </aop:aspect> </aop:config> |
已使用 Microsoft OneNote 2016 创建。rosoft OneNote 2016 创建。
