[TOC]
# AOP
AOP 即 `Aspect Oriented Program` 面向切面编程
首先,在面向切面编程的思想里面,把功能分为**核心业务功能**,和**周边功能**。
所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等
周边功能在Spring的面向切面编程AOP思想里,被定义为**切面**
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别**独立进行开发**
然后把切面功能和核心业务功能 "**编织**" 在一起,这就叫AOP
## 步骤 1 : 先运行,看到效果,再学习
先将完整的 spring 项目(向老师要相关资料),配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。
## 步骤 2 : 模仿和排错
在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。
模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较**正确答案** ( 可运行项目 ) 和自己的代码,来定位问题所在。
采用这种方式,**学习有效果,排错有效率**,可以较为明显地提升学习速度,跨过学习路上的各个槛。
## 步骤 3 : 思路图
1. 功能分两大类,辅助功能和核心业务功能;
2. 辅助功能和核心业务功能**彼此独立**进行开发;
3. 比如登陆功能,即便是没有性能统计和日志输出,也可以正常运行;
4. 如果有需要,就把"日志输出" 功能和 "登陆" 功能 ****编织****在一起,这样登陆的时候,就可以看到日志输出了;
5. 辅助功能,又叫做**切面**,这种能够**选择性的**,**低耦合的**把切面和核心业务功能结合在一起的编程思想,就叫做切面编程。
![](https://box.kancloud.cn/c6a8d939743fccee5a05b31a7f456890_960x609.png)
## 步骤 4 : 准备业务类 ProductService
ProductService
~~~
package com.dodoke.service;
public class ProductService {
public void doSomeService() {
System.out.println("doSomeService");
}
}
~~~
## 步骤 5 : 声明业务对象
在applicationContext.xml中,添加ProductService在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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.dodoke.pojo" />
<bean name="s" class="com.dodoke.service.ProductService"/>
</beans>
~~~
## 步骤 6 : TestSpring
在引入切面之前,调用该业务类
~~~
package com.dodoke.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dodoke.service.ProductService;
public class TestSpring {
public static void main(String[] args) {
// 读取applicationContext.xml配置文件
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
ProductService s = (ProductService)context.getBean("s");
s.doSomeService();
}
}
~~~
运行结果:
![](https://box.kancloud.cn/cfc908c3664003ffc7893bd5a2057338_468x186.png)
## 步骤 7 : 准备日志切面 LoggerAspect
该日志切面的功能是 在调用核心功能之前和之后分别打印日志,切面就是原理图中讲的那些辅助功能。
~~~
package com.dodoke.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
~~~
> `getSignature()`: 获取切点的签名
> `proceed()` :执行切点本来的业务
## 步骤 8 : 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:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.dodoke.pojo" />
<!-- 声明业务对象 -->
<bean name="s" class="com.dodoke.service.ProductService" />
<!-- 声明日志切面 -->
<bean id="loggerAspect" class="com.dodoke.aspect.LoggerAspect" />
<aop:config>
<aop:pointcut expression="execution(* com.dodoke.service.ProductService.*(..))"
id="loggerCutpoint" />
<aop:aspect id="logAspect" ref="loggerAspect">
<aop:around method="log" pointcut-ref="loggerCutpoint" />
</aop:aspect>
</aop:config>
</beans>
~~~
1. 声明日志切面
~~~
<bean id="loggerAspect" class="com.dodoke.aspect.LoggerAspect" />
~~~
2. 结合思路图,配置AOP
指定右边的核心业务功能:
~~~
<aop:pointcut expression="execution(* com.dodoke.service.ProductService.*(..))" id="loggerCutpoint" />
~~~
> 这一句是声明切入点,切入点的 id 叫 loggerCutPoint ,用来标记这个切入点,
> 这个expression表示:满足expression中的方法调用之后,就会去进行切面操作,类似于触发了切面:
> `*` :返回任意类型
> `com.dodoke.service.ProductService.*`:包名以 `com.dodoke.service.ProductService` 开头的类的任意方法
> `(..) `:参数是任意数量和类型
简单说就是,只要`com.dodoke.service`这个包中的ProductService类的任意一个函数被调用,不管你的返回值是什么,都会触发开关,我就会去执行切面,也就是辅助功能,但是辅助功能是什么呢,就是下面两句:
指定左边的辅助功能
~~~
<aop:aspect id="logAspect" ref="loggerAspect">
<aop:around method="log" pointcut-ref="loggerCutpoint" />
</aop:aspect>
~~~
> 这两句是定义了一个切面,上面说只要触发开关,就会去执行切面,就是指的这里的切面,所谓切面,就是一个类中的方法而已。
> id代表这个切面的名字,ref就是指的方法所在的类,method代表的就是方法的名字,`pointcut-ref="loggerCutpoint" `这个就是表示我这个切面是和上面的切点关联起来的(一个切点是可以关联多个切面的,一个切面只能关联一个方法),只要上面的切点被触发,我就会到这里来执行一些辅助功能。
然后通过`aop:config`把业务对象与辅助功能编织在一起。
## 步骤 9 : TestSpring
TestSpring 代码没有发生任何变化,通过配置的方式,把切面和核心业务类编制在了一起。
运行测试,可以发现在编织之后,业务方法运行之前和之后分别会打印日志。
运行结果:
![](https://box.kancloud.cn/9ad28292422ccc7ab029b9b94a26c15f_426x179.png)
## 步骤 10 : 练习-性能统计切面
参考上述的日志切面,做一个性能统计切面,并编织在业务方法上面
注:在业务方法方法中,做循环,以增加耗时
参考:
核心业务里面就搞个费时的操作。
ProductService:
~~~
package com.dodoke.service;
public class ProductService {
public void doSomeService() {
String str = "";
for (int i = 0; i < 1000; i++) {
str += i;
}
System.out.println("doSomeService1:" + str);
}
}
~~~
LoggerAspect:
~~~
package com.dodoke.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
// 运行核心业务类之前的时间
long startTime = System.currentTimeMillis();
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
// 运行核心业务类之后的时间
long endTime = System.currentTimeMillis();
// 总运行时间
long time = endTime - startTime;
System.out.println("耗费时间:" + time);
return object;
}
}
~~~
- 数据库
- 数据库介绍
- MySQL的安装
- SQL
- 表基本操作
- 修改数据语句
- 数据检索操作
- 多表数据操作
- 练习题
- JAVA
- JAVA 介绍
- JAVA 运行原理
- JDK 配置
- 类和对象
- 数据类型
- 变量
- 直接量
- 运算符
- 流程控制
- 数组结构
- 面向对象
- 隐藏和封装
- 深入构造器
- 类的继承
- 多态
- 包装类
- final 修饰符
- 抽象类
- 接口
- 集合框架
- 常用类学习
- 设计模式-单例模式
- 异常处理
- JDBC
- JSP&Servlet
- Web应用
- Tomcat
- JSP
- Scriptlet
- Page 指令
- 包含指令
- 跳转指令
- 用户注册实例
- JSP练习
- 内置对象
- Servlet
- 过滤器
- Web分层思想
- EL表达式
- JSTL
- 分页实现
- AJAX&JSON
- 开发步骤
- 路径问题
- Log4j
- Mybatis框架
- 框架介绍
- Mybatis简单实现
- 表基本操作
- 优化配置文件
- 表字段名与实体类属性名不同的解决方案
- 一对一关联
- 一对多关联
- Spring框架
- IOC/DI
- 注入对象
- 注解方式 IOC/DI
- AOP
- 注解方式AOP
- 注解方式测试
- Spring MVC框架
- Hello SpringMVC
- 视图定位
- 注解方式
- 接受表单数据
- 客户端跳转
- Session
- 中文问题
- 上传文件
- SSM整合
- 整合步骤
- 分页
- PageHelper
- 连接池
- CRUD
- 事务管理
- JSON
- Maven
- 介绍
- 下载与配置MAVEN
- MAVEN仓库
- ECLIPSE中的MAVEN设置
- ECLIPSE下创建MAVEN风格的JAVA项目
- 添加JAR包
- 创建MAVEN风格的JAVA WEB项目
- 创建SSM项目
- 使用ECLIPSE导入一个MAVEN风格的SSM项目
- 教学管理
- 学员名录
- 周测统计
- 20180608
- 20180706
- 20180721
- 课堂作业
- 练习