SSH框架学习之Spring ---- 2、认识AOP ! 警告,前方增强怪!
一、AOP底层分析
需求:根据客户需要,当前的Dao.class中的add()方法,在调用之前需要打印一条"开始打印"语句。
以往的做法:
动add的代码,该怎么改就怎么改。这其实是不符合设计模式的,对于业务的拓展不修改原来的代码,这就是AOP思想。
概念
AOP啥意思呢?拓展功能不修改源代码。这只是通俗理解。
AOP采用横向抽取机制,取代了传统的纵向继承机制(听不懂~)
传统的纵向抽取(古板的糟老头子)
横向抽取机制
我们创造一个需要 “修改的类的对象” 的代理,在本案例中也就是 Dao dao;的一个代理,然后在代理对象中进行逻辑的修改,保证了Dao类还是原来的代码。这里就用到了动态代理的知识。
动态代理,这是自己的博客写的关于动态代理
Spring已经把AOP的底层代码封装好了。接下去就讲如何使用。
二、AOP的操作术语(增强怪出现!)
什么叫增强?
一个方法得到了补充、修改。
本场案例:一个如下的类需要被增强
public class User {
public void add() { System.out.println("add......."); }
public void delete() { System.out.println("delete......."); }
public void query() { System.out.println("query......."); }
public void update() { System.out.println("update......."); }
}
1、连接点JoinPoint:类里面的哪些方法可以被增强,那么这些方法就称为连接点。
add、delete、query和update这四个方法
2、切入点Pointcut(重点):类里面有很多的方法可以被增强,但是我们仅仅增强其中几个。
例如仅仅增强add和update,那么这两个就称为切入点
3、增强(也叫通知)Advice(重要):增强切入点这个动作
比如额外增加一个输出当前时间的功能,就叫增强。
- 前置通知:在方法之前执行
- 后置通知:在方法之后执行
- 异常通知:
- 最终通知:
- 环绕通知:方法之前和之后执行
4、切面Aspect(重要):把增强用到切入点,把增强应用到具体方法的过程
例如把输出时间的功能用到add(),这个过程就叫切面
5、其他,了解即可
三、Spring中AOP的具体操作
案例: 希望在Book的add执行之前,先执行Mybook的add。以前的做法是在Mybook的add方法内,调用book的add方法。
3.1、前期准备:
导入jar包:
创建Spring核心配置文件,引入aop的约束
<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">
创建Book,MyBook对象
public class Book {
public void add() {
System.out.println("add....");
}
}
public class MyBook {
public void before1() {
System.out.println("前置增强...");
}
}
3.2、使用表达式配置切入点
常用的几种表达式:
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
(1) execution(* cn.itcast.aop.Book.add(…)) // 对add进行增强
(2) execution(* cn.itcast.aop.Book.*(…)) //对所以的方法进行增强
(3) execution(* .(…))
(4) execution(* save*(…) // 匹配所以save开头的方法
3.3、具体配置
<?xml version="1.0" encoding="UTF-8" ?>
<!--引入schema约束-->
<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">
<!--1、生成对象-->
<bean id="book" class="cn.itcast.aop.Book"></bean>
<bean id="myBook" class="cn.itcast.aop.MyBook"></bean>
<!--2、配置aop操作-->
<aop:config>
<!--2.1 配置切入点(被增强的方法)
id:给切入点起的名字
expre:通过表达式指定对哪个方法进行增强
-->
<aop:pointcut id="pointcut1" expression="execution(* cn.itcast.aop.Book.*(..)"></aop:pointcut>
<!--2.2 配置切面(增强用在具体方法)
ref:要增强上去的方法所在的bean
-->
<aop:aspect ref="myBook">
<!--配置增强类型
method:哪个方法作为前置增强
pointcut-ref:用到哪个方法上
-->
<aop:before method="before1" pointcut-ref="pointcut1"></aop:before>
</aop:aspect>
</aop:config>
</beans>
测试结果
public void test() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean3.xml");
Book book = (Book) context.getBean("book");
book.add();
}
//输出:
前置增强...
add....
环绕增强
四、AOP的注释写法
配置的写法太繁琐了,于是贴心的Spring又给带来了一种注释写法。
在spring核心配置文件中,开启aop操作扫描
<!--生成对象-->
<bean id="book" class="cn.itcast.aop.Book"></bean>
<bean id="myBook" class="cn.itcast.aop.MyBook"></bean>
<!--开启aop扫描-->
<aop:aspectj-autoproxy/>
在增强类上用注解来实现aop操作
@Aspect
public class MyBook {
@Before(value = "execution(* cn.itcast.aop.Book.*(..))")
public void before1() {
System.out.println("前置增强...");
}
}
总结:代码一下子少了很多有没有!!至此,AOP操作讲述完毕,以后遇到需要添加功能,要想起来Sprng的AOP!!