从头认识Spring-1.2 什么是AOP?为什么需要面向切面编程?

这一章节我们来介绍一下什么是AOP?为什么需要面向切面编程?

1.什么是AOP?(百度百科版)

AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

比如我们最常见的就是日志记录了,举个例子,我们现在提供一个查询学生信息的服务,但是我们希望记录有谁进行了这个查询。如果按照传统的OOP的实现的话,那我们实现了一个查询学生信息的服务接口(StudentInfoService)和其实现 类 (StudentInfoServiceImpl.java),同时为了要进行记录的话,那我们在实现类(StudentInfoServiceImpl.java)中要添加其实现记录的过程。

假如我们要实现的服务有多个呢?那就要在每个实现的类都添加这些记录过程。这样做就会有点繁琐,而且每个实现类都与记录服务日志的行为紧耦合,违反了面向对象的规则。那么怎样才能把记录服务的行为与业务处理过程中分离出来呢?看起来好像就是查询学生的服务自己在进行,但却是背后日志记录对这些行为进行记录,并且查询学生的服务不知道存在这些记录过程,这就是我们要讨论AOP的目的所在。

笔者认为是下面两个图:


在没有使用aop的时候,就像上面,每一个模块都跟日志、事务这些功能交织在一起,无法分离,而且每当我们修改日志的形式的时候,需要修改非常多的代码。



当我们使用了aop,就如上图,输入的数据先进过日志、事务等控制模块,然后再流向实际的业务模块,而日志、事务这些控制模块看起来就像一道切面,切在数据流的中间。


2.为什么需要面向切面编程?

(1)解耦

(2)重复利用代码

(3)便于装卸

(注意,由于代码比较多,而且我是使用maven形式构建项目,因此,具体的代码可以到我的github去查看,本文最底部有我的github地址)

在没有使用aop之前的代码:

package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2;

public class Song {

	private String name;

	public Song(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "the song:" + name;
	}
}

package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2;

public class Singer {
	private Song song = null;

	public Singer() {
		
	}

	public Singer(Song song) {
		this.song = song;
	}

	private void beforeSing() {
		System.out.println("beforeSing");
	}

	public void singTheSong() {
		beforeSing();
		System.out.println(song.toString());
		afterSing();
	}

	private void afterSing() {
		System.out.println("afterSing");
	}

	public static void main(String[] args) {
		new Singer(new Song("my heart will go on")).singTheSong();
	}
}

输出:

beforeSing
the song:my heart will go on
afterSing

当我们在千百个模块里面都需要这种操作前和操作后的日志需要修改,那个时候就是灾难。


使用aop之后:

package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2;

public class Singer {
	private Song song = null;
	
	public Singer() {
	}

	public Singer(Song song) {
		this.song = song;
	}

	public void singTheSong() {
		System.out.println(song.toString());
	}
}


Singer类只需要删除了两个private方法即可


package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2;

public class Song {

	private String name;

	public Song(String name) {
		this.name = name;
	}

	public Song() {
	}

	@Override
	public String toString() {
		return "the song:" + name;
	}
}

Song类需要建立一个默认的构造器,这是由于使用aop,就必须使用cglib,由cglib决定


增加了一个Log类来模拟日志:

package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2;

public class Log {
	public void before() {
		System.out.println("beforeSing");
	}

	public void after() {
		System.out.println("afterSing");
	}
}

测试类:

package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
		"/com/raylee/my_new_spring/my_new_spring/ch01/topic_1_2/ApplicationContext-test.xml" })
public class SingerTest {
	@Autowired
	private ApplicationContext applicationContext;

	@Test
	public void testJackSinger() {
		Singer singer = (Singer) applicationContext.getBean("jack");
		singer.singTheSong();
	}
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
		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="jack"
		class="com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2.Singer">
		<constructor-arg ref="song" />
	</bean>
	<bean id="song"
		class="com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2.Song">
		<constructor-arg value="there will be" />
	</bean>
	<bean id="log"
		class="com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2.Log">
	</bean>
	<aop:config>
		<aop:aspect ref="log">
			<aop:pointcut
				expression="execution(* com.raylee.my_new_spring.my_new_spring.ch01.topic_1_2.Singer.*(..))"
				id="logPointcut" />
			<aop:before method="before" pointcut-ref="logPointcut" />
			<aop:after method="after" pointcut-ref="logPointcut" />
		</aop:aspect>
	</aop:config>

</beans>

主要是配置文件的修改,增加了aop配置类。


输出:

beforeSing

the song:there will be

afterSing


3.aop的优缺点:

优点:

(1)切面的定义放在xml里面,我们可以灵活的配置

(2)易于测试

(3)易于装卸

缺点:

(1)创建对象的流程麻烦了

(2)由于spring大部分采用反射机制来实现,因此性能一定是个问题

(3)由于对象的定义放在xml,对于使用eclipse来重构就会比较麻烦


总结:这一章节我们主要介绍了什么是AOP?为什么需要面向切面编程?


我的github:https://github.com/raylee2015/my_new_spring




  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值