AOP学习笔记(二)——Spring AOP
2017-05-20 11:07
435 查看
1、什么是AOP
AOP(Aspect-Oriented Programming),面向切面编程,是OOP的补充,主要用于将与业务逻辑无关的代码剥离,例如:性能监控、日志记录、权限控制等。
2、实现方案
静态代理
JDK动态代理
CGLIB动态代理
3、现有AOP框架:Spring AOP
前置增强、后置增强、环绕增强(编程式)
接口:
实现类:
前置增强类:
后置增强类:
测试:
当然我们也可以只定义一个增强类,同时实现前置增强和后置增强:
这样,我们在使用时就可以这样写:
在上面定义的GreetingBeforeAndAfterAdvice类,实现了两个接口,springAOP提供了环绕增强,我们只需要实现一个接口:
使用时:
以上即为Sping AOP的编程式基本用法,下面介绍声明式的用法:
首先添加配置文件:
添加注解:
使用:
除了上面介绍了三类增强,还有两类增强:
抛出增强:
引入增强:上面介绍的四种增强是对方法的增强,叫Weaving(织入),这类叫Introduction(引入)。
定义一个新的接口:
引入增强类:
配置:
注意上面的 proxyTargetClass ,表明是否代理目标类,false指代理接口,true指代理类,即使用CGLIB代理。
使用:
AOP框架可以理解为一个拦截器,上面提到的增强类,会对被代理类的所有方法都进行拦截。如果要对特定的方法进行拦截,这个时候就要用到一个重要的工具——Advisor(切面),Advisor(切面)= Advice(增强)+ Pointcut(切点)
首先改造一下原有的接口Greeting:
实现类:
配置文件:
使用:
随着项目的扩大,代理的配置会越来越多,这时候可以让spring AOP框架为我们自动生成代理。
Spring AOP:自动代理(扫描Bean名称)
注意上面的配置项:optimize,若为true,则可为代理生成策略优化(默认是false)。也就是说,如果该类有接口,则使用JDK动态代理;如果没有接口就使用CGLIB代理。
Spring AOP:自动代理(扫描切面配置)
上面的配置中,我们仍然无法解决当项目扩大时,切面的配置增多的问题。这个时候就需要用到AspectJ
4、Spring + AspectJ
1) 基于注解:通过AspectJ execution 表达式拦截方法
配置:
2) 基于注解:通过AspectJ @annotation 表达式拦截方法
首先定义一个注解:
将注解加到要拦截的方法上:
3)基于注解:引入增强
4)基于配置:
AOP(Aspect-Oriented Programming),面向切面编程,是OOP的补充,主要用于将与业务逻辑无关的代码剥离,例如:性能监控、日志记录、权限控制等。
2、实现方案
静态代理
JDK动态代理
CGLIB动态代理
3、现有AOP框架:Spring AOP
前置增强、后置增强、环绕增强(编程式)
接口:
public interface Greeting { public void say(); }
实现类:
public class GreetingImpl implements Greeting{ public void say(){ System.out.println("Hello"); } }
前置增强类:
public class GreetingBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable{ System.out.println("Before"); } }
后置增强类:
public class GreetingAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object result, Method method, Object[] args, Object target) throws Throwable{ System.out.println("After"); } }
测试:
public class Test { public static void main(String[] args){ ProxyFactory proxyFactory = new ProxyFactory(); //创建代理工厂 proxyFactory.setTarget(new GreetingImpl()); //目标对象 proxyFactory.addAdvice(new GreetingBeforeAdvice()); //前置增强 proxyFactory.addAdvice(new GreetingAfterAdvice()); //后置增强 Greeting greeting = (Greeting) proxyFactory.getProxy(); //从代理工厂中获取代理 greeting.say(); //调用代理方法 } }
当然我们也可以只定义一个增强类,同时实现前置增强和后置增强:
public class GreetingBeforeAndAfterAdvice implements MethodBeforeAdvice, AfterReturningAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable{ System.out.println("Before"); } @Override public void afterReturning(Object result, Method method, Object[] args, Object target) throws Throwable{ System.out.println("After"); } }
这样,我们在使用时就可以这样写:
public class Test { public static void main(String[] args){ ProxyFactory proxyFactory = new ProxyFactory(); //创建代理工厂 proxyFactory.setTarget(new GreetingImpl()); //目标对象 proxyFactory.addAdvice(new GreetingBeforeAndAfterAdvice()); //前置增强 和 后置增强 Greeting greeting = (Greeting) proxyFactory.getProxy(); //从代理工厂中获取代理 greeting.say(); //调用代理方法 } }
在上面定义的GreetingBeforeAndAfterAdvice类,实现了两个接口,springAOP提供了环绕增强,我们只需要实现一个接口:
public class GreetingAroundAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable{ before(); Object result = invocation.proceed(); after(); return result; } public void before(){ System.out.println("Before"); } public void after(){ System.out.println("After"); } }
使用时:
public class Test { public static void main(String[] args){ ProxyFactory proxyFactory = new ProxyFactory(); //创建代理工厂 proxyFactory.setTarget(new GreetingImpl()); //目标对象 proxyFactory.addAdvice(new GreetingAroundAdvice()); //环绕增强 Greeting greeting = (Greeting) proxyFactory.getProxy(); //从代理工厂中获取代理 greeting.say(); //调用代理方法 } }
以上即为Sping AOP的编程式基本用法,下面介绍声明式的用法:
首先添加配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" default-lazy-init="true"> <!-- 开启组件自动扫描 --> <context:component-scan base-package="proxy" /> <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="proxy.Greeting" /> <!-- 需要代理的接口 --> <property name="target" ref="greetingImpl"/> <!-- 接口实现类 --> <property name="interceptorNames" value="greetingAroundAdvice"/> <!-- 增强类 --> </bean> </beans>
添加注解:
@Component public class GreetingAroundAdvice implements MethodInterceptor { ... } @Component public class GreetingImpl implements Greeting{ ... }
使用:
public class Test { public static void main(String[] args){ ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml"); Greeting greeting = (Greeting) ctx.getBean("greetingProxy"); greeting.say(); } }
除了上面介绍了三类增强,还有两类增强:
抛出增强:
@Component public class GreetingThrowAdvice implements ThrowsAdvice{ public void afterThrowing(Method method, Object[] args, Object target, Exception e){ System.out.println("-------------Throw Exception------------------"); System.out.println("Target Class: " + target.getClass().getName()); System.out.println("Method Name: " + method.getName()); System.out.println("Exception Message: " + e.getMessage()); System.out.println("----------------------------------------------"); } }
引入增强:上面介绍的四种增强是对方法的增强,叫Weaving(织入),这类叫Introduction(引入)。
定义一个新的接口:
public interface Apology { void saySorry(); }
引入增强类:
@Component public class GreetingIntroAdvice extends DelegatingIntroductionInterceptor implements Apology { @Override public Object invoke(MethodInvocation invocation) throws Throwable{ return super.invoke(invocation); } @Override public void saySorry(){ System.out.println("sorry"); } }
配置:
<bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="proxy.Apology" /> <!-- 需要动态实现的接口 --> <property name="target" ref="greetingImpl"/> <!-- 目标类 --> <property name="interceptorNames" value="greetingIntroAdvice"/> <!-- 引入增强类 --> <property name="proxyTargetClass" value="true"/> <!-- 代理目标类(默认为false,代理接口) --> </bean>
注意上面的 proxyTargetClass ,表明是否代理目标类,false指代理接口,true指代理类,即使用CGLIB代理。
使用:
public class Test { public static void main(String[] args){ ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml"); Greeting greeting = (Greeting) ctx.getBean("greetingProxy"); greeting.say(); Apology apology = (Apology) greeting; apology.saySorry(); } }
AOP框架可以理解为一个拦截器,上面提到的增强类,会对被代理类的所有方法都进行拦截。如果要对特定的方法进行拦截,这个时候就要用到一个重要的工具——Advisor(切面),Advisor(切面)= Advice(增强)+ Pointcut(切点)
首先改造一下原有的接口Greeting:
public interface Greeting { void say(); void goodMorning(); }
实现类:
@Component public class GreetingImpl implements Greeting{ public void say(){ System.out.println("Hello"); } public void goodMorning(){ System.out.println("Good Morning!"); } }
配置文件:
<!-- 开启组件自动扫描 --> <context:component-scan base-package="proxy" /> <!-- 配置一个切面 --> <bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="greetingAroundAdvice"/> <!-- 增强 --> <property name="pattern" value="proxy.GreetingImpl.good.*"/> <!-- 切点(正则表达式) --> </bean> <!-- 配置一个切面 --> <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="greetingImpl"/> <!-- 目标类 --> <property name="interceptorNames" value="greetingAdvisor"/> <!-- 切面 --> <property name="proxyTargetClass" value="true"/> <!-- 代理目标类(默认为false,代理接口) --> </bean>
使用:
public class Test { public static void main(String[] args){ ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml"); Greeting greeting = (Greeting) ctx.getBean("greetingProxy"); greeting.say(); greeting.goodMorning(); } }
随着项目的扩大,代理的配置会越来越多,这时候可以让spring AOP框架为我们自动生成代理。
Spring AOP:自动代理(扫描Bean名称)
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames" value="*Impl"/> <!-- 只为后缀是“Impl”的Bean生成代理 --> <property name="interceptorNames" value="greetingAroundAdvice"/> <!-- 增强 --> <property name="optimize" value="true"/> <!-- 是否对代理生成策略优化 --> </bean>
注意上面的配置项:optimize,若为true,则可为代理生成策略优化(默认是false)。也就是说,如果该类有接口,则使用JDK动态代理;如果没有接口就使用CGLIB代理。
Spring AOP:自动代理(扫描切面配置)
<!-- 配置一个切面 --> <bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="greetingAroundAdvice"/> <!-- 增强 --> <property name="pattern" value="proxy.GreetingImpl.good.*"/> <!-- 切点(正则表达式) --> </bean> <!-- 这个类会自动烧苗所有的切面类,并为其自动生成代理 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> <property name="optimize" value="true"/> </bean>
上面的配置中,我们仍然无法解决当项目扩大时,切面的配置增多的问题。这个时候就需要用到AspectJ
4、Spring + AspectJ
1) 基于注解:通过AspectJ execution 表达式拦截方法
@Aspect @Component public class GreetingAspect { @Around("execution(* proxy.GreetingImpl.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable{ before(); Object result = pjp.proceed(); after(); return result; } public void before(){ System.out.println("Before"); } public void after(){ System.out.println("After"); } }
配置:
<context:component-scan base-package="proxy" /> <aop:aspectj-autoproxy proxy-target-class="true"/>
2) 基于注解:通过AspectJ @annotation 表达式拦截方法
首先定义一个注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Tag { }
将注解加到要拦截的方法上:
@Tag public void say(){ System.out.println("Hello"); }
3)基于注解:引入增强
@Aspect @Component public class GreetingAspect { @DeclareParents(value = "proxy.GreetingImpl", defaultImpl=ApologyImpl.class) private Apology apology; }
4)基于配置:
<bean id="greetingImpl" class="proxy.GreetingImpl"/> <bean id="greetingAspect" class="proxy.GreetingAspect"/> <aop:config> <aop:aspect ref="greetingAspect"> <aop:around method="around" pointcut="execution(* proxy.GreetingImpl.*(..))"/> </aop:aspect> </aop:config>
相关文章推荐
- [原]spring学习笔记9.2-Spring对Aop的支持-annotation的方式
- ITCAST视频-Spring学习笔记(使用CGLIB实现AOP功能与AOP概念解释)
- Spring 2.5.6学习笔记 之 AOP
- Spring 学习笔记 (二)--AOP
- spring AOP 学习笔记
- [原]spring学习笔记9.1.2-Spring对Aop的概念性介绍
- Spring Aop Step-By-Step 学习笔记(下)
- Spring Aop Step-By-Step 学习笔记(上)
- spring学习笔记: Spring AOP
- Spring.NET学习笔记13——AOP的概念(基础篇) Level 200
- [原]spring学习笔记9.1-Spring对Aop的支持-AOP基础篇
- Spring视频学习笔记(4)代理模式及AOP术语
- ITCAST视频-Spring学习笔记(使用Spring配置文件实现AOP)
- Spring.Net实现AOP以及AOP相关概念(学习笔记四)
- Spring Aop Step-By-Step 学习笔记(上)
- ITCAST视频-Spring学习笔记(使用JDK中的Proxy技术实现AOP功能)
- Spring学习笔记3--面向切面(AOP)的例子
- Spring Aop Step-By-Step 学习笔记(上)
- Spring学习笔记(14)----使用Spring的注解方式实现AOP
- Spring的AOP学习笔记