一、AOP的底层原理
AOP的底层原理是动态代理,动态代理有两种方式:JDK动态代理和CGLib动态代理,在有接口的实现类时我们通常用JDK的动态代理方式(默认情况)为类创建代理对象,JDK的动态代理方式可以实现无入侵式的代码扩展,并且可以在不修改源代码的情况下,增强某种方法;而CGLib动态代理不要求目标类实现接口,通过继承的方式动态创建代理对象,Spring的核心报集成了CGLib需要的包,无需另外导入JAR包
二、AOP的实现
因为Spring AOP中的代理对象由IoC容器自动生成,所以开发者无须过多关注代理对象生成的过程,只需选择连接点、创建切面、定义切点并在XML文件中添加配置信息即可。
Spring AOP的实现有两种配置:基于xml配置和基于注解的方式的配置
AOP配置概念:在切面配置切入点(被增强的类)和增强的关系
切面是指关注点形成的类(关注点是指类中重复的代码),通常是指封装的、用于横向插入系统的功能类(如事务管理、日志记录等)
1、基于XML的AOP实现:
Spring AOP的XML元素
<aop:config>AOP的根元素
<aop:aspect>配置切面:id属性用于定义该切面的唯一标识,ref属性用于引用普通的Spring Bean,通常会配置5中通知,分别为前置通知、后置通知、环绕通知、返回通知和异常通知。
<aop:pointcut>配置切点:作为根元素的子元素时改切入点是全局的,可被多个切面共享,作为<aop:aspect>的子元素时表示对当前切面有效,定义<aop:pointcut>通常会指定id和expression属性(用于指定切入点关联的切入点表达式)
execution(modifiers-pattern?ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern) throws-pattern?)
参数说明
modifiers-pattern:表示定义的目标方法的访问修饰符,如public、private等。
ret-type-pattern:表示定义的目标方法的返回值类型,如void、String等。
declaring-type-pattern:表示定义的目标方法的类路径,如com.itheima.jdk.UserDaoImpl。
name-pattern:表示具体需要被代理的目标方法,如add()方法。
param-pattern:表示需要被代理的目标方法包含的参数。
throws-pattern:表示需要被代理的目标方法抛出的异常类型。
在Spring中使用XML实现Spring AOP
1、需要引入Maven的aspectjrt包的依赖和aspectjweaver包的依赖
<!-- aspectjrt包的依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<!-- aspectjweaver包的依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
2、创建接口UserDao,并在该接口中编写添加、删除、修改和查询的方法。
3、创建UserDao接口的实现类UserDaoImpl,实现UserDao接口中的方法
4、创建XmlAdvice类,用于定义通知(插入的切面程序代码,切面的实现)
5、创建applicationContext.xml文件,在该文件中引入AOP命名空间,使用<bean>元素添加Spring AOP的配置信息。
<!-- 注册bean省略,下面内容为配置Spring AOP-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(*
com.itheima.demo03.UserDaoImpl.*(..))"/><!-- 指定切点 -->
<aop:aspect ref ="xmlAdvice"><!-- 指定切面 -->
<aop:before method="before" pointcut-ref="pointcut"/><!-- 指定前置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>-- 指定环绕方式 -->
<aop:after-throwing method="afterException" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/><!-- 指定后置通知 -->
</aop:aspect>
</aop:config>
6、创建测试类TestXml,测试基于XML的AOP实现
public class TestXml{
public static void main(String[] args){
ApplicationContext context=newClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao=context.getBean("userDao",UserDao.class);
userDao.delete();
userDao.insert();
userDao.select();
userDao.update();
}
}
2.基于注解的AOP实现
Spring Aop的注解概况:
1、创建接口UserDao,并在该接口中编写添加、删除、修改和查询的方法
创建UserDao接口的实现类UserDaoImpl,实现UserDao接口中的方法
(创建接口用于测试中调用方法,而接口的实现类通过bean中的配置完成接口的实现,利用了控制反转DI)
2、创建AnnoAdvice类,用于定义通知(插入的切面程序代码,切面的实现)
@Aspect
public class AnnoAdvice {
@Pointcut("execution( * com.itheima.demo03.UserDaoImpl.*(..))")
// 代码
@Before("poincut()")
//代码
@AfterReturning("poincut()")
//代码
@Around("poincut()")
//代码
@AfterThrowing("poincut()")
// 代码
@After(“poincut()")
// 使用以上注解分别定义切点、前置通知、返回通知、环绕通知、异常通知、后置通知
}
3、创建applicationContext-Anno.xml文件,在该文件中引入AOP命名空间,使用<bean>元素添加Spring AOP的配置信息
<!-- 注册Bean -->
<bean name="userDao" class="com.itheima.demo.UserDaoImpl"/>
<bean name="AnnoAdvice" class="com.itheima.demo.AnnoAdvice"/>
<!-- 开启@aspectj的自动代理支持 -->
<aop:aspectj-autoproxy/>
4、创建测试类TestAnnotation,用于测试基于注解的AOP实现(和xml方式的测试类基本相同)