目录
AOP(Aspect Oriented Programming),面向切面编程,通过预编译方式和运行期间动态代理实现实现在不修改源代码的情况下给程序动态统一添加某种特定功能的一种技术。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
以模拟租房业务来讲解AOP技术的两种实现形式
AOP的实现有两种形式:
基于非注解(XML配置)形式实现
基于注解形式实现
1、引入核心依赖
除了AOP依赖,还需要将基础核心依赖引入
在pom.xml中引入
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<kotlin.version>1.0.0</kotlin.version>
<!--spring 依赖中版本要保持一致,在properties中配置好spring的版本-->
<spring.propety>4.1.7.RELEASE</spring.propety>
</properties>
<!--Spring的AOP jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.propety}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--spring核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.propety}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.propety}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.propety}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.propety}</version>
</dependency>
2、给定一个房东类
/**
* 房东
*/
public class Landlord {
public void service() {
System.out.println("签合同");
System.out.println("收钱");
}
}
3、中介类
/**
* 中介
*/
public class Broker {
public void service1(){
System.out.println("看房子");
}
public void service2(){
System.out.println("谈价钱");
}
public void service3(){
System.out.println("给钥匙");
}
}
4.1、基于XML配置形式实现
在XML引入AOP的约束(在资源文件夹下面新建一个配置文件AOPSpringContext3.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"
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.xsd">
</beans>
execution函数介绍
在通知中通过value属性定义切点,通过execution函数,可以定义切点的方法切入
1、切入点:实际增强的方法
2、常用的表达式
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
(1)execution(* com.tulun.bean.Book.show(..)) 表类里面的某一个方法
(2)execution(* com.tulun.bean.Book.*(..)) 表类某个包里类所有方法
(3)execution(* *.*(..)) 表示所有
例:
-匹配所有类public方法 execution(public *.*(..))
-匹配指定包下所有类方法 execution(* com.tulun.bean.*(..)) (不包含子包)
- execution(* com.tulun.bean..*(..)) (包含包、子包下所有类)
-匹配指定类所有方法 execution(* com.tulun.bean.Book.*(..))
-匹配实现特定接口所有类方法 execution(* com.tulun.bean.Book+.*(..))
-匹配所有com开头的方法 execution(* com*(..))
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"
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.xsd">
<!--将类交给容器管理-->
<bean id="landlord" class="com.che.AOP.Landlord"/>
<bean id="broker" class="com.che.AOP.Broker"/>
<!--配置AOP操作-->
<aop:config >
<!--
aop:pointcut标签
配置切入点
对于要进行增强的连接点称之为切入点
id属性:取名称
expression:切入点表达式
execution表达式
-->
<aop:pointcut id="pointcut1" expression="execution(* com.che.AOP.Landlord.service(..))"/>
<!--
aop:aspect标签
配置切面
把增强应用到切入点的过程
ref属性:指定增强
id属性:取名称
order属性:给多个增强排序
-->
<aop:aspect ref="broker">
<!--配置增强类型:前置增强-->
<aop:before method="service1" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
<!--配置增强类型:前置增强(aop:before)-->
<!--<aop:before method="service1" pointcut-ref="pointcut1"/>-->
<!--后置增强(aop:after )-->
<!--<aop:after method="service2" pointcut-ref="pointcut1"/>-->
<!--最终增强(aop:after-returning )-->
<!--<aop:after-returning method="service3" pointcut-ref="pointcut1"/>-->
<!--异常增强(aop:after-throwing)-->
<!--<aop:after-throwing method="service4" pointcut-ref="pointcut1"/>-->
<!--环绕增强-->
<!--<aop:around method="service5" pointcut-ref="pointcut1"/>-->
</beans>
增强类型:
aop:around
aop:before
aop:after-throwing
aop:after
aop:after-returning
测试使用:测试类AOPTest
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("AOPSpringContext3.xml");
Landlord landlord = (Landlord)context.getBean("landlord");
landlord.service();
System.out.println(landlord);
}
}
执行结果:
看房子
签合同
收钱
各种类型增强如下:
<!--配置增强类型:前置增强(aop:before)-->
<aop:before method="service1" pointcut-ref="pointcut1"/>
<!--后置增强(aop:after )-->
<aop:after method="service2" pointcut-ref="pointcut1"/>
<!--最终增强(aop:after-returning )-->
<aop:after-returning method="service3" pointcut-ref="pointcut1"/>
<!--异常增强(aop:after-throwing)-->
<aop:after-throwing method="service4" pointcut-ref="pointcut1"/>
<!--环绕增强-->
<aop:around method="service5" pointcut-ref="pointcut1"/>
4.2、基于注解形式实现AOP操作
在xml配置文件中(AOPSpringContext4.xml)开启扫描注解,开启AOP操作
<?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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.tulun.Spring.AOP"/>
<!--开启AOP操作-->
<aop:aspectj-autoproxy/>
</beans>
在增强类上添加注解
import org.springframework.stereotype.Component;
/**
* 房东
*/
//将房东类交给容器进行管理也需要添加注解
@Component
public class Landlord {
public void service() {
System.out.println("签合同");
System.out.println("收钱");
}
}
/**
* 中介
*/
@Component
@Aspect
//当前类开启AOP操作
public class Broker {
//前置增强注解,@Before
@Before(value = "execution(* com.tulun.Spring.AOP.Landlord.service(..))")
public void service1(){
System.out.println("看房子");
}
}
@Aspect 注解添加在类上,表示当前类是增强类
@Before注解添加在方法上,表示前置增强
@Before(value = "execution(* com.tulun.Spring.AOP.Landlord.service(..))")
关于增强注解:
//前置增强注解,@Before
@Before(value = "execution(* com.tulun.Spring.AOP.Landlord.service(..))")
//后置增强
@After(value = "execution(* com.tulun.Spring.AOP.Landlord.service(..))")
//最终增强
@AfterReturning(value = "execution(* com.tulun.Spring.AOP.Landlord.service(..))")
@AfterThrowing(value = "execution(* com.tulun.Spring.AOP.Landlord.service(..))") //异常增强
@Around(value = "execution(* com.tulun.Spring.AOP.Landlord.service(..))")//环绕增强