目标(Target):被通知(被代理)的对象
注1:完成具体的业务逻辑
通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)
注2:完成切面编程
代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),
例子:外科医生+护士
注3:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的
切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点。
(也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)
适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)
如何实现AOP
目标对象只负责业务逻辑代码
通知对象负责AOP代码,这二个对象都没有AOP的功能,只有代理对象才有
接下来代码演示
1.导入pom依赖
<properties> <junit.vesion>4.12</junit.vesion> <servlet.vesion>4.0.0</servlet.vesion> <!--spring 5.0.1.RELEASE --> <spring.vesion>5.0.1.RELEASE </spring.vesion> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.vesion}</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.vesion}</version> <scope>provided</scope> </dependency> <!--spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.vesion}</version> </dependency> <!--spring -core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core </artifactId> <version>${spring.vesion}</version> </dependency> <!--spring-orm --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm </artifactId> <version>${spring.vesion}</version> </dependency> <!--spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web </artifactId> <version>${spring.vesion}</version> </dependency> <!--spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects </artifactId> <version>${spring.vesion}</version> </dependency> </dependencies>
applicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 目标 :被通知(被代理)的对象(专注具体的核心业务逻辑)--> <bean id="bookBizTarget" class="com.hmc.spring02.biz.BookBizImpl"> </bean> <!--通知 :在某种特定的连接点上所执行的动作(AOP代码写在这里) --> <!--示例一:前置通知 --> <bean id="beforeAdvice" class="com.hmc.spring02.advice.BeforeAdvice"> </bean> <!--实例二:后置通知 --> <bean id="afterAdvice" class="com.hmc.spring02.advice.AfterAdvice"></bean> <!-- 实例三:环绕通知 --> <bean id="rounAdvice" class="com.hmc.spring02.advice.RoundAdvice"></bean> <!--实例四:异常通知 --> <bean id="exceptionAdvice" class="com.hmc.spring02.advice.ExceptionAdvice"></bean> <!--实例五 :适配器=通知+切入点 --> <bean id="RegexpMethodPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!--通知 --> <property name="advice"> <ref bean="afterAdvice"/> </property> <!--切入点 --> <property name="patterns"> <list> <value>.*buy</value> </list> </property> </bean> <!--代理对象 --> <bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--目标 --> <property name="target"> <ref bean="bookBizTarget"/> </property> <!--通知 --> <property name="interceptorNames"> <list> <!-- <value>beforeAdvice</value>--> <value>afterAdvice</value> <!-- <value>rounAdvice</value> --> <!-- <value>exceptionAdvice</value> --> <!-- <value>RegexpMethodPointcutAdvisor</value> --> </list> </property> <!--代理对象实现的 接口列表 --> <property name="proxyInterfaces"> <list> <value>com.hmc.spring02.biz.IBookBiz</value> </list> </property> </bean> </beans>
IBookBiz.java
package com.hmc.spring02.biz; public interface IBookBiz { // 购书 public boolean buy(String userName, String bookName, Double price); // 发表书评 public void comment(String userName, String comments); }
BookBizImpl.java
package com.hmc.spring02.biz; import com.hmc.spring02.advice.PriceException; public class BookBizImpl implements IBookBiz { public BookBizImpl() { super(); } public boolean buy(String userName, String bookName, Double price) { // 通过控制台的输出方式模拟购书 if (null == price || price <= 0) { throw new PriceException("book price exception"); } System.out.println(userName + " buy " + bookName + ", spend " + price); return true; } public void comment(String userName, String comments) { // 通过控制台的输出方式模拟发表书评 System.out.println(userName + " say:" + comments); } }
前置通知
package com.hmc.spring02.advice; import java.lang.reflect.Method; import java.util.Arrays; import org.springframework.aop.MethodBeforeAdvice; /** * 前置通知 * @author Administrator * */ public class BeforeAdvice implements MethodBeforeAdvice { /** * @param method 目标对象的方法 * @param params 目标对象的方法参数 * @param target 目标对象 */ @Override public void before(Method method, Object[] params, Object target) throws Throwable { //目标对象的类的全路径名 String className=target.getClass().getName(); //目标对象类中所调用的方法名 String methodName=method.getName(); System.out.println(className+","+methodName+" 执行参数:"+Arrays.toString(params)); } }
后置通知
package com.hmc.spring02.advice; import java.lang.reflect.Method; import java.util.Date; import org.springframework.aop.AfterReturningAdvice; /** * 后置通知 * @author Administrator * */ public class AfterAdvice implements AfterReturningAdvice { /** * @param returnValue 目标对象方法的返回值 * @param mehtod 目标对象执行的方法 * @param params 目标对象方法的执行参数 * @param target 目标对象 */ @Override public void afterReturning(Object returnValue, Method method, Object[] params, Object target) throws Throwable { System.out.println("后置通知"+"返回值:"+returnValue+"+[销售返利]["+new Date().toLocaleString()+"]返利3元"); } }
环绕通知
package com.hmc.spring02.advice; import java.lang.reflect.Method; import java.util.Arrays; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * 环绕通知 * @author Administrator * */ public class RoundAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { //目标对象方法参数 Object[] params = invocation.getArguments(); //目标对象 Object target = invocation.getThis(); //目标对象执行的方法 Method method = invocation.getMethod(); System.out.println("[环绕通知]"+target.getClass().getName()+","+method.getName()+"执行参数"+Arrays.toString(params)); //执行方法 Object returnVlaue= invocation.proceed(); System.out.println("[环绕通知]返回值"+returnVlaue); return returnVlaue; } }
异常通知
ExceptionAdvice
package com.hmc.spring02.advice; import org.springframework.aop.ThrowsAdvice; public class ExceptionAdvice implements ThrowsAdvice{ public void afterThrowing(PriceException ex ) { System.out.println("[异常通知]"+ex.getMessage()); } }
PriceException
package com.hmc.spring02.advice; public class PriceException extends RuntimeException{ public PriceException() { super(); // TODO Auto-generated constructor stub } public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public PriceException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public PriceException(String message) { super(message); // TODO Auto-generated constructor stub } public PriceException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } }
适配器