AOP应用
一、AOP概述
1、什么是AOP
- 面向切面编程它其实就是oop纵向编程的补充,什么是切面说白就是将非核心逻辑处理抽离到一个可复用的独立切面模块里面,以后可以根据不同的方位横向织入到横向地位的对象方法里面,此就是面向切面编程
2、AOP的组成及本质
-
AOP的组成就是核心关注点和横切关注点
- 核心关注点:其实就是横向对象的目标方法
- 横切关注点:其实就是非核心逻辑处理就是横切关注点,就是一个切面
-
AOP本质
- 就是将横切关注点与核心关注点相分离,根据一定的需求将横切关注点织入到核心关注点
二、AOP的底层实现
1、实现原理
-
使用动态代理技术实现
2、实现动态代理有两种写法
- JDK动态代理
- Cglib动态代理
代理模式的具体实现
三、AOP语术
-
Joinpoint
- 连接点
- SpringAOP的连接点其实就是目标对象的方法
- 连接点
-
Pointcut
- 切点
- 根据一定的规则那些连接点起作用,此连接点就是切点
- 切点
-
Advice
-
根据一定的方位织入增强代码逻辑
-
方位
-
前置方位织入
- 当核心方法执行之前织入执行增强
-
后置方位织入
- 当核心方法执行之后织入执行增强
-
环绕方位织入
- 当核心方法执行之前后织入执行增强
-
抛出异常方位织入
- 当核心方法抛出异常后织入执行增强
。。。
-
-
-
-
目标类对象
- Target object
- 代理目标类对象
- Target object
-
AOP Proxy
-
aop的代理对象
-
Aspectj
- 就是一个切面
- 切面=增强+切点
- 增强
- 非核心代码逻辑处理+织入方位
- 切点
- 增强
- 切面=增强+切点
- 就是一个切面
四、Spring如何实现aop编程
- 传统式的FactoryBean动态代理实现aop
- 通过xml文件配置FactoryBean动态代理方式实现aop
- 通过Aspectj注解实现aop
- 直接通过aop:aspect标签去实现aop
- 直接通过advisor(通知者)标签去实现aop
五、传统式FactoryBean动态代理实现aop
1、spring提供五种增强类
-
Before(前)
- org.apringframework.aop.MethodBeforeAdvice
-
After-returning(返回后)
-
org.springframework.aop.AfterReturningAdvice
-
After-throwing(抛出后) org.springframework.aop.ThrowsAdvice
public void afterThrowing(Exception ex) public void afterThrowing(RemoteException) public void afterThrowing(Method method, Object[] args, Object target, Exception ex) public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
-
Arround(周围)
- org.aopalliance.intercept.MethodInterceptor
-
Introduction(引入)
org.springframework.aop.IntroductionInterceptor
2、如何使用增强类
-
实现aop编程
-
定义一个目标类对象
package com.gec.target; public class Hadoop { public void eatting(String name) { System.out.println("1 大象正在吃 "+name); } public void eatting2(String name) { System.out.println("2 大象正在吃 "+name); int a=100/0; } public void eatting3(String name) { System.out.println("3 大象正在吃 "+name); } }
-
定义三个增强类
-
前置增强
package com.gec.advice; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; /* * 定义一个前置增强 * */ public class MyBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { String name=null; for (Object object : objects) { name= (String) object; } System.out.println(name+"已经准备好了,大象过来吃吧!!!"); } }
-
后置增强
package com.gec.advice; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class MyAfterReturningAdvice implements AfterReturningAdvice { /* * 后置增强 * */ @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("我已经饱了,不吃了!"); } }
-
抛出异常增强
package com.gec.advice; import org.springframework.aop.ThrowsAdvice; public class MyThrowsAdvice implements ThrowsAdvice { public void afterThrowing(Exception ex) { System.out.println("触发抛出异常的增强处理"); } }
-
-
通过Spring提供动态工厂代理类实现aop
-
通过ProxyFactory产生动态代理对象
package com.gec.app; import com.gec.advice.MyAfterReturningAdvice; import com.gec.advice.MyBeforeAdvice; import com.gec.advice.MyThrowsAdvice; import com.gec.target.Hadoop; import org.springframework.aop.framework.ProxyFactory; public class MainTest { public static void main(String[] args) { //目标类的对象 Hadoop hadoop=new Hadoop(); //增强类的对象 MyBeforeAdvice advice=new MyBeforeAdvice(); MyAfterReturningAdvice advice2=new MyAfterReturningAdvice(); MyThrowsAdvice advice3=new MyThrowsAdvice(); ProxyFactory pf=new ProxyFactory(); //注入增强类对象 pf.addAdvice(advice); pf.addAdvice(advice2); pf.addAdvice(advice3); //注入目标类对象 pf.setTarget(hadoop); Hadoop proxyHadoop= (Hadoop) pf.getProxy(); proxyHadoop.eatting("香蕉"); proxyHadoop.eatting("西瓜"); proxyHadoop.eatting2("香蕉"); proxyHadoop.eatting2("西瓜"); proxyHadoop.eatting3("香蕉"); proxyHadoop.eatting3("西瓜"); } }
-
3、如何使用切点类
-
什么是切点?
-
根据一定的规则作用于方法,此方法就是切点
-
切点类型
-
StaticMethodMatherPointcut
- 指明那个类里面的那个方法起切点作用
- 处理者: StaticMethodMatcherPointcutAdvisor
-
AnnotationMatchingPointcut
- 指明那个注解作用于方法起切点作用
- 使用DefaultPointcutAdvisor处理
-
JdkRegexpMethodPointcut
- 通过正则表达式作用于方法起切点作用
- RegexpMethodPointcutAdvisor处理者对象
-
AspectJExpressionPointcut
- 通过Aspectj的表达式作用于方法起切点作用
- AspectJExpressionPointcutAdvisor处理者对象
-
-
如何使用切点类
-
定义一个切点类
-
只针对hadoop类下的eatting方法起作用
package com.gec.advisor; import com.gec.target.Hadoop; import org.springframework.aop.ClassFilter; import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; import java.lang.reflect.Method; /* * 定义一个切点类 * */ public class HadoopAdvisor extends StaticMethodMatcherPointcutAdvisor { /* * 指明那个方法起作用 * */ @Override public boolean matches(Method method, Class<?> targetClass) { if(method.getName().equals("eatting")) { return true; } return false; } /* * 必须针对Hadoop目标类起作用 * */ @Override public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class<?> clazz) { return clazz.isAssignableFrom(Hadoop.class); } }; } }
-
-
如何使用切点类
-
创建一个切点类对象
-
将增强类对象注入到切点类
-
将切点类对象注入到ProxyFactory对象里面
-
代码如下
package com.gec.app; import com.gec.advice.MyAfterReturningAdvice; import com.gec.advice.MyBeforeAdvice; import com.gec.advice.MyThrowsAdvice; import com.gec.advisor.HadoopAdvisor; import com.gec.target.Hadoop; import org.springframework.aop.framework.ProxyFactory; public class MainTest { public static void main(String[] args) { //目标类的对象 Hadoop hadoop=new Hadoop(); //增强类的对象 MyBeforeAdvice advice=new MyBeforeAdvice(); MyAfterReturningAdvice advice2=new MyAfterReturningAdvice(); MyThrowsAdvice advice3=new MyThrowsAdvice(); //创建一个切点类对象 HadoopAdvisor hadoopAdvisor=new HadoopAdvisor(); //注入增强类对象 hadoopAdvisor.setAdvice(advice); ProxyFactory pf=new ProxyFactory(); //注入一个切点类对象 pf.addAdvisor(hadoopAdvisor); /*//注入增强类对象 pf.addAdvice(advice); pf.addAdvice(advice2); pf.addAdvice(advice3);*/ //注入目标类对象 pf.setTarget(hadoop); Hadoop proxyHadoop= (Hadoop) pf.getProxy(); proxyHadoop.eatting("香蕉"); proxyHadoop.eatting("西瓜"); proxyHadoop.eatting2("香蕉"); proxyHadoop.eatting2("西瓜"); proxyHadoop.eatting3("香蕉"); proxyHadoop.eatting3("西瓜"); } }
-
-
六、通过xml文件配置工厂代理bean对象
1、简介
- 就是通过xml文件配置工厂代理bean对象
- 主要是通过
IOC容器
去管理目标类对象、增强类对象、切点类对象、工厂bean对象
2、具体如何实现
-
编写beans.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置目标类的bean对象--> <bean id="hadoop" class="com.gec.target.Hadoop" /> <!--增强类的bean对象--> <bean id="beforeAdvice" class="com.gec.advice.MyBeforeAdvice"/> <!--配置切点类的bean对象--> <bean id="hadoopAdvisor" class="com.gec.advisor.HadoopAdvisor" > <property name="advice" ref="beforeAdvice"/> </bean> <!--配置ProxyFactoryBean对象--> <bean id="hadoopProxyBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="hadoop" /> <property name="interceptorNames"> <value>hadoopAdvisor</value> </property> <property name="proxyTargetClass"> <value>true</value> </property> </bean> </beans>
七、通过使用AspectJ注解实现aop
1、简介
-
通过AspectJ注解实现aop编程
-
依赖AspectJ表达式实现
-
AspectJ常用注解
-
针对方位增强注解
@Before:前置增强,相当于BeforeAdvice的功能。 @AfterReturning:后置增强 @Around:环绕增强 @AfterThrowing:抛出增强 @After:增强,不管是抛出异常或者是正常退出,该增强都会得到执 行,该增强没有对应的增强接口,可以把它看成ThrowAdvice和 AfterReturningAdvice的混合物,一般用于释放资源,相当于 try{}finally{}的控制流
-
如何定义一个切面注解
@AspectJ
-
-
AspectJ表达式
-
AspectJ表达式函数
execution:用于匹配方法执行的连接点; within:用于匹配指定类型内的方法执行; target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类 型匹配,这样就不包括引入接口也类型匹配; args:用于匹配当前执行的方法传入的参数为指定类型的执行方法; @within:用于匹配所以持有指定注解类型内的方法; @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有 指定的注解; @args:用于匹配当前执行的方法传入的参数持有指定注解的执行; @annotation:用于匹配当前执行方法持有指定注解的方法; bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定 名称的Bean对象的执行方法;
-
2、通过AspectJ注解实现AOP
-
定义一个目标类
package com.gec.target; /* * 定义一个目标类对象 * */ public class Hadoop { public void eatting(String name) { System.out.println("1 大象正在吃 "+name); } public void eatting2(String name) { System.out.println("2 大象正在吃 "+name); } public void eatting3(String name) { System.out.println("3 大象正在吃 "+name); } }
-
定义一个切面
-
切面=增强+切点
编写一个Aspectj表达式
package com.gec.aspectj; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; /* * 定义一个aop切面 * 切面=增强+切点 * */ @Aspect public class HadoopAspectj { /* * 切点的作用规则:com.gec.target.Hadoop类下的eatting方法 * */ @Before("execution(* com.gec.target.Hadoop.eatting(..))") public void beforeEatting() { System.out.println("食物已经准备好了,大象过来吃吧!!!"); } }
-
-
配置beans.xml
- 使用aop:aspectj-autoproxy标签自动注入切面到工厂代理bean对象
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--实现自动将aspectj的切面注入到工厂代理bean对象--> <aop:aspectj-autoproxy /> <!--定义目标类bean对象--> <bean id="hadoop" class="com.gec.target.Hadoop" /> <bean id="preAspectJ" class="com.gec.aspectj.HadoopAspectj" /> </beans>
-
操作类
package com.gec.app; import com.gec.target.Hadoop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainTest { public static void main(String[] args) { //获取IOC容器对象 ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); Hadoop proxyHadoop= (Hadoop) ctx.getBean("hadoop"); proxyHadoop.eatting("香蕉"); proxyHadoop.eatting("西瓜"); proxyHadoop.eatting2("香蕉"); proxyHadoop.eatting2("西瓜"); proxyHadoop.eatting3("香蕉"); proxyHadoop.eatting3("西瓜"); } }
八、通过aop:aspect标签实现切面
1、简介
- 直接在xml文件定义aop:aspect标签来定义一个切面
2、如何使用aop:aspect标签
-
定义一个增强类
-
此类不需要实现或者继承某些父类或者接口
package com.gec.advice; /* * 此类就是增强类 * 特点 * 1、不需要实现某个接口 * 2、不需要使用某些注解 * * */ public class MethodAdvice { public void beforeAdive() { System.out.println("食物已经准备好了,大象过来吃吧!!!"); } }
-
-
配置beans.xml文件
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy /> <!--定义一个目标类对象--> <bean id="hadoop" class="com.gec.target.Hadoop" /> <!--定义一个增强类的bean对象--> <bean id="methodAdvice" class="com.gec.advice.MethodAdvice" /> <aop:config> <!--定义一个切面 注入:增强类bean对象 --> <aop:aspect ref="methodAdvice"> <!-- aop:before:前置方法 method:增强类的方法名 pointcut:切点表达式 --> <aop:before method="beforeAdive" pointcut="execution(* com.gec.target.Hadoop.*(..))" /> </aop:aspect> </aop:config> </beans>
-
操作类
package com.gec.app; import com.gec.target.Hadoop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainTest { public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); Hadoop proxyHadoop= (Hadoop) ctx.getBean("hadoop"); proxyHadoop.eatting("香蕉"); proxyHadoop.eatting2("香蕉"); proxyHadoop.eatting3("香蕉"); } }
九、通过advisor标签实现aop
1、简介
- 通过advisor标签可以实现切面
- 定义一个实现方位的增强类
- 在配置advisor标签定义
- 注入增强类bean对象
- 配置切点表达式
2、举例用法
-
定义一个目标类对象
package com.gec.target; /* * 定义一个目标类对象 * */ public class Hadoop { public void eatting(String name) { System.out.println("1 大象正在吃 "+name); } public void eatting2(String name) { System.out.println("2 大象正在吃 "+name); } public void eatting3(String name) { System.out.println("3 大象正在吃 "+name); } }
-
定义一个增强类
-
此增强类实现方位接口
package com.gec.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class MyBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("食物已经准备好了,大象过来吃吧!!!"); }}
-
-
配置beans.xml文件
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy /> <bean id="hadoop" class="com.gec.target.Hadoop" /> <bean id="beforeAdvice" class="com.gec.advice.MyBeforeAdvice" /> <aop:config> <aop:advisor advice-ref="beforeAdvice" pointcut="execution(* com.gec.target.Hadoop.*(..))"/> </aop:config></beans>