一、简介
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
二、执行原理图
三、SpringAOP的本质总结
我们将要进行功能扩展相关的材料以及对应的组织规则告诉Spring容器,Spring容器帮我们动态创建一个代理对象。我们直接从Spring容器中获取代理对象完成功能开发。
四、Schema-based
package com.bjsxt.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
//在这个方法中进行代码扩展即可
System.out.println("---------->我是后置通知");
}
}
package com.bjsxt.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
//在这个方法中进行代码扩展即可
System.out.println("---------->我是后置通知");
}
}
package com.bjsxt.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class RoundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕之前");
//放行
Object proceed = methodInvocation.proceed();
System.out.println("环绕之后");
return proceed;
}
}
package com.bjsxt.advice;
import org.springframework.aop.ThrowsAdvice;
public class ThrowAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) throws Throwable{
System.out.println("我是异常通知");
}
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.bjsxt.service.impl.UserServiceImpl"></bean>
<!--前置通知对象-->
<bean id="beforeAdvice" class="com.bjsxt.advice.BeforeAdvice"></bean>
<!--后置通知对象-->
<bean id="afterAdvice" class="com.bjsxt.advice.AfterAdvice"></bean>
<!--环绕通知对象-->
<bean id="roundAdvice" class="com.bjsxt.advice.RoundAdvice"></bean>
<!--异常通知对象-->
<bean id="throwAdvice" class="com.bjsxt.advice.ThrowAdvice"></bean>
<!--织入横切面-->
<aop:config>
<!--指定切点-->
<aop:pointcut id="pt1" expression="execution(* com.bjsxt.service.impl.UserServiceImpl.bb())"/>
<!--给指定切点追加通知-->
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="pt1"></aop:advisor>
<aop:advisor advice-ref="afterAdvice" pointcut-ref="pt1"></aop:advisor>
<aop:advisor advice-ref="roundAdvice" pointcut-ref="pt1"></aop:advisor>
<aop:advisor advice-ref="throwAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
</beans>
五、Aspectj
AspectJAdvice
package com.bjsxt.advice;
import org.aspectj.lang.ProceedingJoinPoint;
public class AspectJAdvice {
//前置通知
public void before(){
System.out.println("-----前置通知-----");
}
//前置通知
public void after(){
System.out.println("-----后置通知-----");
}
//前置通知
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("-----环绕通知前-----");
Object proceed = point.proceed();
System.out.println("-----环绕通知后-----");
return proceed;
}
//前置通知
public void throwsAdvice(){
System.out.println("-----异常通知-----");
}
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.bjsxt.service.impl.UserServiceImpl"></bean>
<!--配置通知类对象-->
<bean id="aspect" class="com.bjsxt.advice.AspectJAdvice"></bean>
<aop:config>
<aop:aspect ref="aspect">
<aop:pointcut id="pt1" expression="execution(* com.bjsxt.service.impl.UserServiceImpl.bb())"/>
<!--前置通知-->
<aop:before method="before" pointcut-ref="pt1"></aop:before>
<!--后置通知-->
<aop:after method="after" pointcut-ref="pt1"></aop:after>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="pt1"></aop:around>
<!--异常通知-->
<aop:after-throwing method="throwsAdvice" pointcut-ref="pt1"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
@Aspectj在扫描时与Aspectj顺序不一样
@Aspectj:环绕在外,前后置通知在内
Aspectj:环绕在内,前后置通知在外
注解方式
package com.bjsxt.advice;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
@Aspect
public class AspectJAdvice {
//切点
@Pointcut("execution(* com.bjsxt.service.impl.AccountServiceImpl.zq(..))")
public void pt(){}
//后置通知
@After("pt()")
public void after(){
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String format = dateFormat.format(date);
System.out.println("用户在"+format+"完成了转账操作");
}
}
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!--IOC+DI扫描-->
<context:component-scan base-package="com.bjsxt.service,com.bjsxt.pojo,com.bjsxt.advice"></context:component-scan>
<!--加载扫描AOP中注解驱动-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--事务注解驱动-->
<tx:annotation-driven></tx:annotation-driven>
<!--引入属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--[1] 建立数据库连接-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${m_driver}"></property>
<property name="url" value="${m_url}"></property>
<property name="username" value="${m_username}"></property>
<property name="password" value="${m_password}"></property>
</bean>
<!--[2] 获取sqlsessionfactory对象-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.bjsxt.pojo"></property>
</bean>
<!--[3] 扫描mapper文件-->
<bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<property name="basePackage" value="com.bjsxt.mapper"></property>
<!--自动创建了Peoplemapper Bean对象-->
</bean>
<!--声明式事务的配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>