什么是面向切面编程 |
面向对象的编程主要注重核心业务,而面向切面编程主要关注一些不是核心的业务,但又是必须的辅助功能,比如一个完整的系统中,记录平时系统运行时抛出的异常,需要我们去记录,以便我们对系统尽快的修复。这就是我们常用的日志。如果对一些要求比较重要的数据操作,事务是不可少的,如金融系统,这样的数据很重要,每步操作都很重要,我们就应该用到事务处理。这就是我们常用的事务处理。可根据你的系统数据的重要性,有选择的应用。还用一个常用的就是安全验证了,它也是常用的,对于不同的页面,访问的身份也不一样。这就是我们常用的身份验证。以上这些不是针对特定那个业务模块的,可能针对所有的模块。它们只是一些附加的功能,相对模块的主功能而言。如果在每个模块中都夹杂着这些不是核心业务的代码,看起来与核心业务有点关系,但这样处理,会对以后的维护比较头疼。同时也违背了面向对象的一条原则,自己对自己负责。本不属于这个方法的业务也放在了其中。这样的代码不仅难维护,重用性也不好,耦合度也比较大。内聚性也比较低。这样的代码眼前可能不会有什么麻烦,但给后期的维护人员带来了麻烦。
面向方面的编程主要是辅助核心业务的,它并不是核心业务,但它又是不可缺少的。我们可以这样理解它与面向对象思想的联合使用。其实面向方面编程就是把那些夹杂在核心业务方法里面的代码抽取出来并模块化,把它们单独看成一个模块功能.来与核心业务共同完成比较完善的功能.
面向方面编程( Aspect-Oriented Programming,AOP)很早就出现了,它与spring的Ioc结合使用,更加体现了aop的强大功能所在.在讲它与spring结合使用之前先说几个难听,难懂的概念.它为什么不命名一些容易理解的概念了,因为aop很早就有人对它们命名了, 所以spring中讲的aop也不例外.在jboss,AspectJ…中都有aop这个概念.概念都一样的
原文地址:参考文章
AOP中的基本概念 |
-
aspect(切面)
实现了cross-cutting功能,是针对切面的模块。最常见的是logging模块,这样,程序按功能被分为好几层,如果按传统的继承的话,商业模型继承日志模块的话根本没有什么意义,而通过创建一个logging切面就可以使用AOP来实现相同的功能了。
-
jointpoint(连接点
连接点是切面插入应用程序的地方,该点能被方法调用,而且也会被抛出意外。连接点是应用程序提供给切面插入的地方,可以添加新的方法。比如以上我们的切点可以认为是findInfo(String)方法。
-
advice(处理逻辑)
advice是我们切面功能的实现,它通知程序新的行为。如在logging里,logging advice包括logging的实现代码,比如像写日志到一个文件中。advice在jointpoint处插入到应用程序中。以上我们在MyHandler.java中实现了advice的功能
-
pointcut(切点)
pointcut可以控制你把哪些advice应用于jointpoint上去,通常你使用pointcuts通过正则表达式来把明显的名字和模式进行匹配应用。决定了那个jointpoint会获得通知。
-
introduction
允许添加新的方法和属性到类中。
-
target(目标类)
是指那些将使用advice的类,一般是指独立的那些商务模型。比如以上的StudentInfoServiceImpl.
-
proxy(代理类)
使用了proxy的模式。是指应用了advice的对象,看起来和target对象很相似。
-
weaving(插入)
是指应用aspects到一个target对象创建proxy对象的过程:complie time,classload time,runtime
IDE |
IDE
使用IDEA2016.1.2
关于开发步骤部分,请查看本文的Spring的配置文件部分,已经给出充分的注释。
项目管理采用Maven ,用到的依赖见下面的pom 文件内容。 |
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parent>
<groupId>com.springinaction</groupId>
<artifactId>example-code</artifactId>
<version>3.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.springinaction</groupId>
<artifactId>springidol-aop</artifactId>
<version>3.0.0</version>
<packaging>jar</packaging>
<name>Spring in Action Spring Idol - AOP</name>
<url>http://www.manning.com/walls4</url>
<dependencies>
<dependency>
<groupId>${spring.group}</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>${spring.group}</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>${spring.group}</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.6</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
相关bean 的编写,本文用到的bean 如下 |
`Instrument`
package com.springinaction.springidol;
public interface Instrument {
public void play();
}
`Instrumentalist`
package com.springinaction.springidol;
public class Instrumentalist implements Performer {
public void perform() throws PerformanceException {
instrument.play();
}
private Instrument instrument;
public void setInstrument(Instrument instrument) {
this.instrument = instrument;
}
public Instrument getInstrument() {
return instrument;
}
}
Performer
package com.springinaction.springidol;
public interface Performer {
void perform() throws PerformanceException;
}
PerformanceException
package com.springinaction.springidol;
public class PerformanceException extends Exception {
private static final long serialVersionUID = 1L;
}
Guitar
package com.springinaction.springidol;
public class Guitar implements Instrument {
public void play() {
System.out.println("Strum strum strum");
}
}
Audience
package com.springinaction.springidol;
public class Audience {
public void takeSeats() { //<co id="co_takeSeats"/>
System.out.println("The audience is taking their seats.");
}
public void turnOffCellPhones() { //<co id="co_turnOffCellPhones"/>
System.out.println("The audience is turning off their cellphones");
}
public void applaud() { //<co id="co_applaud"/>
System.out.println("CLAP CLAP CLAP CLAP CLAP");
}
public void demandRefund() { //<co id="co_demandRefund"/>
System.out.println("Boo! We want our money back!");
}
}
Spring的配置 |
<?xml version="1.0" encoding="UTF-8"?>
<!--1.确定需要引入哪些明明空间-->
<!--1.1 Spring beans-->
<!--1.2 Spring Context-->
<!--1.3 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">
<!--2.创建一个乐师对象-->
<!--2.1我们假设名称为frank-->
<bean id="frank" class="com.springinaction.springidol.Instrumentalist">
<!--2.2指定该乐师能够演奏的乐器,这是代码里面约定的-->
<property name="instrument">
<!--2.3这里采用内部bean的方式为其注入属性-->
<bean class="com.springinaction.springidol.Guitar"></bean>
</property>
</bean>
<!--3.注册切面方法所在类-->
<bean id="audience" class="com.springinaction.springidol.Audience"></bean>
<!--4.配置切面-->
<!--4.1声明配置的根节点-->
<aop:config>
<!--4.2创建或者说是声明切面-->
<aop:aspect ref="audience">
<!--4.3使用aop:before1-->
<aop:before method="takeSeats"
pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"></aop:before>
<!--4.4使用aop:before2-->
<aop:after-returning method="turnOffCellPhones"
pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"></aop:after-returning>
<!--4.5使用aop:after-returning-->
<aop:after-returning method="applaud"
pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"></aop:after-returning>
<!--4.6使用aop:after-throwing-->
<aop:after-throwing method="demandRefund"
pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"></aop:after-throwing>
</aop:aspect>
</aop:config>
<!--开始测试吧-->
</beans>
junit测试类的内容 |
package com.springinaction.springidol;
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;
/**
* Created by Administrator on 2016/5/28.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:com/springinaction/springidol/spring-idol-myxml.xml"})
public class MyTest {
@Autowired
ApplicationContext context;
/**
* 测试切面及切点是否工作
*/
@Test
public void testAspect() throws PerformanceException {
Performer frank = (Performer) context.getBean("frank");
frank.perform();
}
}
junit的运行结果 |