Spring系列文章
Spring框架-1(基础)
Spring框架-2(IOC上)
Spring框架-3(IOC下)
Spring框架-4(AOP)
Spring框架-5(JDBC模板&Spring事务管理)
Spring框架-6(SpringMvc)
Spring框架-7(搭建SSM)
Spring框架-8(SpringMVC2)
前面提到AOP可以在不修改源代码的前提下,对程序进行增强,AOP的底层实现其实是JDK的动态代理和CGLIB。那么这篇博客将入门AOP使用配置文件的用法和注解的用法。
我们这篇文章要学什么先看下思维导图吧:
动手之前先了解一些术语
- Joinpoint(连接点) -- 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
- Pointcut(切入点) -- 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
- Advice(通知/增强) -- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
- Introduction(引介) -- 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field
- Target(目标对象) -- 代理的目标对象
- Weaving(织入) -- 是指把增强应用到目标对象来创建新的代理对象的过程
- Proxy(代理) -- 一个类被AOP织入增强后,就产生一个结果代理类
- Aspect(切面) -- 是切入点和通知的结合,以后咱们自己来编写和配置的
配置文件入门程序
1.需求
现在项目的某一个dao层对数据库有save,update,delete功能,现在我需要不改变功能代码的情况下,再这些功能前面输出log。
2.aspectJ的开发包
- com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
- spring-aspects-4.2.4.RELEASE.jar
使用IDEA创建一个Spring项目,IDEA 会下载导入除了红框框以外的所有jar包。当然红框框哪个包也是需要的。既然IDEA不hi自动导入那么我们可以自己去下载导入。
3.创建包结构,编写具体的接口和实现类,切面类
-
com.zhong.aopdemo
CustomerDao -- 接口
CustomerDaoImpl -- 实现类
MyAspectXml -- 切面类
public interface CustomDao {
void save();
void update();
void delete();
}
public class CustomDaoImpl implements CustomDao {
@Override
public void save() {
System.out.println("保存信息");
}
@Override
public void update() {
System.out.println("更新信息");
}
@Override
public void delete() {
System.out.println("删除信息");
}
}
public class MyAspectXml {
// 定义通知
public void log() {
System.out.println("记录日志...");
}
}
4.配置文件
<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 http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="customDao" class="com.zhong.aopdemo.CustomDaoImpl"/>
<bean id="myAspectXml" class="com.zhong.aopdemo.MyAspectXml"/>
<aop:config>
<!-- 引入切面类 -->
<aop:aspect ref="myAspectXml">
<!-- 定义通知类型:切面类的方法和切入点的表达式 -->
<aop:before method="log" pointcut="execution(public * com.zhong.aopdemo.CustomDaoImpl.save(..))"/>
<aop:before method="log" pointcut="execution(public * com.zhong.aopdemo.CustomDaoImpl.update(..))"/>
<aop:before method="log" pointcut="execution(public * com.zhong.aopdemo.CustomDaoImpl.delete(..))"/>
</aop:aspect>
</aop:config>
</beans>
5.运行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config.xml")
public class Demo {
@Resource(name="customDao")
private CustomDao customDao;
@Test
public void test() {
customDao.save();
customDao.update();
customDao.delete();
}
}
运行结果
记录日志...
保存信息
记录日志...
更新信息
记录日志...
删除信息
看到结果,没问题那么我们的入门程序成功写完了。我们现在成功在save,update,delete这三个方法前记录了日志
分析一些术语
切入点的表达式
再配置切入点的时候,需要定义表达式,重点的格式如下:execution(public * *(..)),具体展开如下:
-
切入点表达式的格式如下:
- execution([修饰符] 返回值类型 包名.类名.方法名(参数))
修饰符可以省略不写,不是必须要出现的。
返回值类型是不能省略不写的,根据你的方法来编写返回值。可以使用 * 代替。
-
包名例如:com.itheima.demo3.BookDaoImpl
- 首先com是不能省略不写的,但是可以使用 * 代替
- 中间的包名可以使用 * 号代替
- 如果想省略中间的包名可以使用 ..
类名也可以使用号代替,也有类似的写法:DaoImpl
方法也可以使用 * 号代替
参数如果是一个参数可以使用*号代替,如果想代表任意参数使用 ..
AOP的通知类型
- 前置通知
- 在目标类的方法执行之前执行。
- 配置文件信息:<aop:after method="before" pointcut-ref="myPointcut3"/>
- 应用:可以对方法的参数来做校验
- 最终通知
- 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
- 在配置文件中编写具体的配置:<aop:after method="after" pointcut-ref="myPointcut3"/>
- 应用:例如像释放资源
- 后置通知
- 方法正常执行后的通知。
- 在配置文件中编写具体的配置:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut2"/>
- 应用:可以修改方法的返回值
- 异常抛出通知
- 在抛出异常后通知
- 在配置文件中编写具体的配置:<aop:after-throwing method="afterThorwing" pointcut-ref="myPointcut3"/>
- 应用:包装异常的信息
- 环绕通知
- 方法的执行前后执行。
- 在配置文件中编写具体的配置:<aop:around method="around" pointcut-ref="myPointcut2"/>
- 要注意:目标的方法默认不执行,需要使用ProceedingJoinPoint对来让目标对象的方法执行。
注解方式实现
1.注解定义切面类
- 添加切面和通知的注解
- @Aspect -- 定义切面类的注解
- 通知类型(注解的参数是切入点的表达式)
- @Before -- 前置通知
- @AfterReturing -- 后置通知
- @Around -- 环绕通知
- @After -- 最终通知
- @AfterThrowing -- 异常抛出通知
@Component
@Aspect
public class MyAspectXml {
// 定义通知
@Before("execution(public * com.zhong.aopdemo.CustomDaoImpl.save(..))")
public void log() {
System.out.println("记录日志...");
}
}
2.修改配置文件,给使用的类加上Component注解
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.zhong.aopdemo"/>
<!--在配置文件中开启自动代理-->
<aop:aspectj-autoproxy/>
</beans>
测试结果
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config.xml")
public class Demo {
@Resource(name="customDao")
private CustomDao customDao;
@Test
public void test() {
customDao.save();
}
}
结果
记录日志...
保存信息
这就成功了。其实写到这里都是一些基础的东西。从配置文件到注解方式,可见注解是多么的强大。多么的方便,如果各位不太懂注解,建议先去熟悉熟悉注解