1 概念
Spring Framework是一个流行的JAVA开源框架,是一个轻量级的JEE解决方案,可以一站式构建企业级应用。
分层架构
组件化
集成框加
Spring通过四种策略来简化JAVAEE开发:
1 基于POJO的轻量级、最小侵入式开发
2 通过IOC和AOP实现松耦合
3 通过AOP和惯例实现声明式事务编程
4 通过AOP和模板消除样板式代码
这说明AOP的概念非常重要。需要理解,学会使用。
从Spring4.0开始,简化了它的学习过程,基于Spring4.x构建的SpringBoot项目可以极大的简化开发中相关配置的复杂性
Spring整体架构
1 核心容器
2 上下文
3 面向切面
4 DAO,ORM
5 Web模块,MVC框架
6 测试模块
常用依赖
spring-context
spring-core
spring-beans
spring-aop
aopalliance
spring-expression
common-logging
junit
产生Spring容器的方法
用注解方式
//产生容器
ApplicationContext cxt = new AnnotationConfigApplicationContext(XXXXConfig.class);
//获取bean
Hello hello = (Hello)cxt.getBean("hello");
用xml配置方式
//产生容器
ApplicationContext cxt = new ClassPathXmlApplicationContext("classpath:/applicationConfig.xml");
//获取bean
Hello hello = (Hello)cxt.getBean("hello");
AOP===Aspect-oriented Programming面向切面的编程
业务与切面增强方式
核心业务在完成时,会有一些通用的复用的代码,如日志,安全性,异常处理,事务等
这些动作,与业务无关,却为业务模块所共同调用的逻辑或是责任,单独地封装起来,以便于减少系统的重复代码,方便维护,降低模块之间的耦合,并有利于未来的可操作性和可维护性。这些就叫切面。
AOP会把软件系统分为两个部分:核心业务点和横切关注点
横切业务点的特点是
!!! 1 发生在核心业务点的多处
!!! 2 各种都基本相似,如权限,日志,认证,事务处理等
实现AOP的技术原理===代理
1 动态代理技术
2 静态织入的方式
AOP核心概念
切面(Aspect):在哪里做和做什么的集合,是一个整体概念,也就是横切关注点的模块化结果
连接点(JoinPoint):在程序执行过程中某个特定的点,即在哪里做
通知(Advice):即动作,也就是做什么【也就是增强的那一部分动作,或者可增加的那一部分动作,如果是要加日志,就是写日志的动作;如果要做事务,就是开启或是关闭事务的动作】
切入点(Pointcut):匹配连接点的一个判断。一般就是一个签名或是声名。即“在哪里做的集合”。核心知识点是:切点表达式
目标对象(Target Object):即将要被增强的对象或是方法。也就是“对谁做”。
AOP代理(对象)(Proxy):在运行过程中,由AOP框架组装并创建出来的对象,也就是用切面包装以后的目标对象,又叫代理对象,它好象是目标对象,但比目标对象功能更强。
织入(Weaving)切面和原方法,编译,加载和运行的全过程叫织入。
通知的类型
1 前置通知
2 返回后通知
3 抛出异常后通知
4 后通知
5 环绕通知
实例
0 创建项目后的POM依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- AspectJ start-->
<dependency>
<groupId>org.aspectj</groupId>
<!-- runtime包 -->
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<!-- 织入包 -->
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
<!-- 用于动态代理,基于类的代理 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1</version>
</dependency>
<!-- AspectJ end-->
</dependencies>
1 音乐会接口
package com.fhzheng.demo.concert;
/**
* 音乐会表演接口
* 【这是一个经典的AOP示例,在《Spring实战》中给出来的】
* @author fhzheng
*
*/
public interface Performance {
/**
* 表演方法
*/
void perform();
}
2 音乐会实现类【用于模拟核心业务】
package com.fhzheng.demo.concert;
/**
* 音乐会具体类
* @author fhzheng
*
*/
public class Concert implements Performance {
@Override
public void perform() {
System.out.println("音乐会开始...");
}
}
3 音乐会观众类【用于模拟横切关注点,即切面】
package com.fhzheng.demo.concert;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 音乐会切面类,观众的核心业务是看表演,但仍然需要进行周边切面任务:如检票,落座,鼓掌,或在不成功的情况下要求退票
* 用注解的方式可以进行ASPECT
* 用XML配置的方式也可以进行ASPECT
* @author fhzheng
*
*/
//@Aspect
public class Audience {
/**
* 切点定义 或叫 切点签名
*/
//@Pointcut("execution(* com.fhzheng.demo.concert.*.*(..))")
public void perform() {}
/**
* 前置通知
* 即在具体的方法之前执行
*/
//@Before("perform()")
public void checkIn() {
System.out.println("验票检票...");
}
/**
* 前置通知
* 即在具体的方法之前执行
*/
//@Before("perform()")
public void takeSeats() {
System.out.println("观众入座...");
}
/**
* 返回通知
* 即在具体的方法之后执行
*/
//@AfterReturning("perform()")
public void applause() {
System.out.println("掌声响起...");
}
/**
* 异常通知
* 即在具体的方法出现了异常时执行
*/
//@AfterThrowing("perform()")
public void demandRefund() {
System.out.println("要求退款...");
}
}
4 spring核心配置与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"
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-4.3.xsd">
<!-- 开启自动代理 -->
<aop:aspectj-autoproxy />
<!-- 注册业务bean和切面 -->
<bean id ="concert" class="com.fhzheng.demo.concert.Concert"></bean>
<bean id ="audience" class="com.fhzheng.demo.concert.Audience"></bean>
<!-- 配置切面 -->
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut expression="execution(* com.fhzheng.demo.concert.*.*(..))" id="perform"/>
<aop:before method="checkIn" pointcut-ref="perform"/>
<aop:before method="takeSeats" pointcut-ref="perform"/>
<aop:after-returning method="applause" pointcut-ref="perform"/>
<aop:after-throwing method="demandRefund" pointcut-ref="perform"/>
</aop:aspect>
</aop:config>
</beans>
5 测试
package com.fhzheng.demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import com.fhzheng.demo.concert.Performance;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringAop1ApplicationTests {
@Test
public void contextLoads() {
}
@Test
public void aopTest() {
ApplicationContext cxt =new ClassPathXmlApplicationContext("classpath:/applicationContext.xml");
Performance concert = cxt.getBean(Performance.class);
concert.perform();
}
}
后记
和之前的IOC一样,有两种生成容器对象的方式,即
1 可以用注解方式来生成
2 可以用XML配置方式来生成
从理解上来讲,用XML方式更容易理解,初学可以多自己来配置一下,加深理解。
XML配置方式也更容易体现解耦。