Spring:
1. 是什么:是一个IOC和AOP的容器框架;
2. Spring框架的核心组件:
(1) Bean:依赖注入(在IOC容器中实现)
Bean包装的是数据;
bean的顶级接口是BeanFactory(较少);
两种IOC容器的实现:ApplicationContext和BeanFactory;
ApplicationContext的主要实现类:
ClassPathXmlApplicationContext(类下加载)
FileSystemXmlApplicationContext(文件下加载)
(2) Context:
Context就是一个Bean关系的集合;
Context的顶级父类是ApplicationContext;
Context作为Spring的IOC容器,基本上整合了Spring的大部分功能;
(3) Core:
Core就是发现、建立和维护每个Bean之间关系所需要的一些工具;
包括很多关键类:定义了资源的访问方式...;
(4) SpEL(spring的表达式语言)
3. 基础思想:
(1) 依赖注入(DI)/控制反转(IOC):用于管理Java对象之间的依赖关系;
① 解释和优点:
反转资源获取的方向(查找的被动形式)
即容器直接向组件推送资源,而非组件发起请求
将组件对象的控制权从代码本身转移到web容器。
解耦合,更利于扩展
② 前世今生:
1) 分离接口与实现:(原始社会:直接制作一把斧子(斧子的形状、大小、...均需知道))
2) 工厂模式:(封建社会:工厂调用(让工厂制作))
3) IOC:(社会主义,按需分配:直接放一个放斧子的框就行)
③ 在IOC容器中配置Bean:
测试代码:
④ 举例:
HelloWorld.java:
测试:
1. 创建Spring的IOC容器:(id标识bean--给谁调用?,class反射类--调用操作谁?)
2. 从IOC容器中获取bean实例:
3. 使用bean:
applicationContext.xml:
⑤ IOC的注入方式:
1) 构造器注入:(使用<constructor-arg></constructor-arg>)
2) 属性注入(set方法,最常见):(使用<property></property>)
3) 使用p命名空间注入:
<bean id=”helloWorld” class=”com.atguigu.spring.helloworld.HelloWorld” p:name=”username” p:value=”atguigu”/>
⑥ IOC容器完成的事情:
1) 创建对象
2) 为属性赋值
⑦ 注入细节:
1) 字面量:<value/>或value=””;
2) 引用:<ref>(在一个bean中注入另一个bean对象)
3) <null/>
4) 集合属性:<list>和<set>
5) bean的自动装配:(一般除了超大项目外,很少使用自动装配)
使用autowire属性;(byType和byName)
6) ...
7) Bean之间的关系
a. 继承:parent
b. 依赖:depends-on
8) 抽象bean:(作为模板,只能被继承,不能被实例化)
9) Bean的作用域:(默认为singleton)
单例(Singleton):整个应用中,只创建一个bean实例
原型(Prototype):每次注入时,都会创建一个bean实例
请求(Request):web应用中,为每次请求创建一个bean实例
会话(Session):web应用中,为每次会话创建一个bean实例
代码体现:
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class myBean{...}
Xml体现:
<bean id= “” class=”” scope=””>
10) spring的表达式语言(SpEL):使用#{...}作为定界符:为动态复制提供了便利;
11) Bean的生命周期:
a. 创建bean实例;
b. 为bean属性赋值和引用;
c. 调用bean初始化方法;
d. bean可以使用;
e. 容器关闭,bean销毁;
12) Bean的声明:
a. @Component组件:基本注解;
b. @Service:业务逻辑层使用;
c. @Resository:数据访问层使用;
d. @Controller:表现层使用;
13) 使用@Autowired(@Inject和@Resource)自动装配bean
(2) 对IOC使用注解的方式注入对象:(XML方式优先和注解方式)
① applicationContext.xml文件中:添加<context:annotation-config/>;
② 在属性面前加入@Autowired(自动注解)注解;
(3) 面向切面编程(AOP):
① 背景:越来越多的非业务需求(日志和验证)使得代码混乱和代码分散;
② 原理:将复杂问题分解成不同的方面,使用动态代理原理
图:
③ AOP术语:
1) 切面(Aspect):横切关注点后的特殊对象;
2) 通知(Advice):切面必须完成的工作;
3) 目标(Target):被通知的对象;
4) 代理(Proxy):通知后创建的对象;
5) 连接点(Joinpoint):程序执行的每个特定位置;
6) 切点(pointcut):AOP通过切点定位到特定的连接点;
④ AspectJ(最完整最流行的AOP框架)
⑤ 步骤:
1) 加入jar包;
2) 在配置文件中加入aop的命名空间
3) 基于注解的方式:
a. 在配置文件中加入:
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
b. 把横切关注点的代码抽象到切面的类中:
a) 切面是一个IOC的bean(加入@Component);
b) 切面需要加入@Aspect注解;
c. 在类中声明各种通知:
a) 声明一个方法;
b) 在方法前加入@before(“execution(* 方法())”)
d. 五种类型通知注解:
a) @Before:前置通知
在方法执行之前执行的通知
@Before(“execution(* 类.方法(..))”)
b) @After:后置通知
在连接点完成之后的通知
@After(“execution(* *.*(..))”)
c) @AfterRunning:返回通知
(切点表达式中有returning属性)
@After(pointcut=“execution(* *.*(..))” , returning=”result”)
d) @AfterThrowing:异常通知
只有连接点抛出异常时才执行异常通知(throwing属性)
@AfterThrowing(pointcut=“execution(* *.*(..))” ,
throwing=”e”)
e) @Around:环绕通知
(是所有通知类型中功能最为强大的,能够全面控制连接点,甚至可以控制是否执行连接点)
要求连接点的参数类型是ProceedingJoinPoint;
需调用jointPoint.proceed();
⑥ 指定切面的优先级:加入@Order(0)或@Order(1)...
⑦ Spring中的事务管理:
1) 事务的概念:一系列的动作,要么动作都完成,要么都不完成;
举例:a给b转500(a-500,b+500)
2) 作用:确保数据的完整性和一致性;
3) 事务的关键属性(ACID):
a. 原子性
b. 一致性
c. 隔离性
d. 持久性
4) 用事务通知声明式地管理事务:(配置方式)
5) 使用@Transactional注解声明式地管理事务
(4) AOP的注入方式(XML方式和AspectJ注解方式优先)
① 注解配置业务类:
1) @Component(“s”):表示这是一个bean -> 直接可以调用getBean(“s”)即可;
② 注解配置切面:
1) @Aspect注解表示这是一个切面;
2) @Component表示这是一个bean,有Spring管理;
3) @before...@Around(“execution(* 类名.*(..))”):表示对这个类的所有方法进行切面操作。
③ Bean配置文件中:
1) 定位业务类和切面类:
<context:component-scan base-packege=”切面类”/>
<context:component-scan base-packege=”业务类”/>
2) 进行切面设置:
<aop:aspectj-autoprocy/> -> (在Spring IOC容器中启用AspectJ注解支持)
(5) AOP的注入方式(XML方式)
1) 声明切面:<aop:config>中创建<aop:aspect>
<bean id=”loggingAspect” class=””></bean>
<aop:config>
<aop:aspect id=”” ref=”loggingAspect”></aop”aspect>
</aop:config>
2) 声明切面点:<aop:pointcut>
3) 声明通知:<aop:before/>,<aop:after/>
4) 声明引入:<aop:declare-matching/>
(6) AOP的AspectJ注解声明切面:
① 声明切面:只需在IOC容器中将切面声明为Bean实例;
② 在该注解中,切面就是一个带有@Aspect注解的Java类;
③ (环绕通知)通知访问当前连接点的细节:添加(ProceedingJoinPoint joinPoint);
@Around(value = “execution(* *.*(..))”)
public object log(ProceedingJoinPoint joinPoint){
前日志;
Object object = joinPoint.proceed(); //连接点执行
后日志;
return object;
}