Spring期末复习

本文最后更新于:2023年3月23日 上午

一、原理:

IOC(控制反转):(面向对象编程)
控制权由内部应用程序的代码转移到外部容器中去,控制权反转,由外部容器来控制程序之间的关系
DI(依赖注入):
内部应用程序依赖于外部容器给它创建并注入需要的外部资源,比如程序、组件之间的依赖关系等
AOP:(面向切面编程)
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使其各个部分之间的耦合度降低,提高程序可重用性跟开发效率

二、Spring Bean作用域:

bean标签中有个属性叫“scope”,它就是作用域

1,singleton

单例嘛,自然是所有对Bean的请求只要id与bean的定义匹配,就会返回bean的同一个实例

2,prototype

每次对Bean请求的时候Spring IOC都会创建一个新的作用域(tip:对于有状态的Bean应该用prototype反之singleton)

3,request

针对每次http请求,Spring容器会根据相关的bean的定义创建一个全新的并且只在当前request内有效的实例

4,session

针对http session起作用,Spring会根据相关的bean的定义创建一个全新的并且只在当前session内有效的实例
误区:session不是关闭浏览器就结束生命周期,关闭浏览器只是jsessionid重建。服务器内存中的数据不会马上清理。

5,global session

类似http session作用域不过仅基于portlet的web应用中才有意义

三、Spring注入方式:

1,构造器注入

Spring采用反射的方式,通过构造方法完成注入:
1)引入Spring的支持
2)知道具体的类的构造方法跟参数,方便Spring创建对象
3)在代码中写入Spring配置文件:

1
2
3
String configLocation="applicationContext.xml";
ApplicationContext context=new ClassPathXmlApplicationContext(configLocation);
Something thing=context.getBean("thing",Something.class);

tip:在Spring中一切资源都是bean

2,setter注入(最主流做法)

setter注入利用Java Bean规范:
1)将构造方法设置为无参构造,然后利用setter注入为其设置的新值,也是通过java的反射技术实现
2)配置文件中设置:

1
2
3
4
5
<bean id="role" class="com.etc.entity.Role">
<property name="id" value="20211212"></property>
<property name="name" value="yy"></property>
<property name="sex" value="girl"></property>
</bean>

3,接口注入

有时资源并非来自自身系统而是来自于外界,此时数据库连接资源可以在Tomcat下配置,然后跳过JNDI的方式去获取

四、懒加载:

懒加载意思是容器启动的时候不创建对象,第一次要使用对象的时候才创建并且初始化
作用就是避免一旦bean非常多的时候Spring一启动就得一个个去实例化
懒加载只针对Spring创建bean为单例时才有意义,因为只有单例模式时才在Spring启动的时候创建bean,多例bean原本就是懒加载

配置方式:

1,xml配置,在bean中加个属性lazy-init="true",想要全局配置就在beans标签上加个default-lazy-init="true"
2,注解配置,在创建新对象的方法前加上@Lazy

五、自动装配:

先说手动装配是什么:

1
2
3
4
5
6
7
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="people" class="com.kuang.pojo.Peopel">
<property name="name" value="张三"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>

我们在peoplebean中手动装配了cat跟dog的bean,这就是手动装配

所以自动装配:

1,xml配置

在bean中加一个属性autowire="byName"
自动装配的方式有byNamebyTypeconstructordefaultno
byName:就是查询实体类中所有 setter方法的名字跟自己bean的id相同的自动装配
no:默认,不自动装配
byType:靠属性类型和bean的class进行识别。要保证 符合该type的bean唯一,否则会报错
constructor:靠构造函数入参的属性名进行识别

2,注解

1)得先在xml里开启注解,加上标签<context:annotation-config/>
2)在类中声明变量的前面加上@Autowired,比如

1
2
@Autowired
private Cat cat;

当然,你xml中的bean必须得有id为cat,class为Cat的标签~
tip:注解方式自动装配的时候会先按id找相同的,如果有多个相同的就会去下一个属性找相同比如class
ttip:使用@Autowired(required= false)时,这等于告诉 Spring:在找不到匹配 Bean 时也不报错

六、面向切面:

advice(通知):新的公共功能。
joinpoint(连接点):通知能够插入代码的位置。代码会在连接点前、后或环绕(ProceedingJoinPoint)插入。
pointcut(切点): 通知插入代码的方法。代码会在切点指定的方法中插入。
aspect(切面):切点+通知(pointcut+advice)。
weaving:织入。

1,xml配置

1)创建一个接口,来个实现类
2)创建切面类,里面包含了beforeMethodafteraround什么的方法
3)配置AOP

1
2
3
4
5
6
7
<aop:config>
<aop:pointcut expression="execution(* service.StudentService.*(..))" id="mypc"/>
<aop:aspect ref="aspect" order="1">
<aop:before method="beforeMethod" pointcut-ref="pointcut">
……
</aop:aspect>
</aop:config>

4)配置测试类

1
2
3
ApplicationContext context=new ClassPathXmlApplicationContext(configLocation);
Something thing=context.getBean("thing",Something.class);
thing.add(10,5);//假设他是个加法……

2,注解配置

1)通知类升级为切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect // 1、将通知类升级为切面类
@Component
public class FreeAdvice {
// 2、定义切点(利用标识方法,来承载切点注解)

@Pointcut("execution(* com.etc.PhoneService.*(..))")
public void pointcut() {
}

// 3、把切点和通知做绑定
// 前置通知
@Before("pointcut()")
public void beforeLog(JoinPoint point) {
System.out.println("准备执行移动业务");
}

// 后置通知
@After("pointcut()")
public void afterfee() {
System.out.println("本次业务费用为10元");
}
}

2)xml配置一下

1
2
<!-- 开启AOP的注解模式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3)然后跟上面一样来个测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package test;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.etc.service.PhoneService;
public class TestPhone {
@Autowired
private PhoneService phoneService;
@Test
public void test() {

phoneService.call();
phoneService.send_sms();
}

}

3,动态代理,暂略

七、事务:

1,事务是一组操作,要么全部成功,要么全部失败。

spring支持事务的提交和回滚。有些框架,事务是必须的。框架中的应用:拦截器

2,事务特性 ACID

原子性
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性
指系统从一个正确的状态,迁移到另一个正确的状态.简单理解就是:事务前后数据的逻辑性必须是合理的。
隔离性
所有的数据库客户端都可以针对某张表同时执行事务。这些事务是隔离的。其实就是多线程并发。
持久性
一旦事务提交后,就无法回滚了。

3,事务分类

声明式事务(推荐,@Transactional
编程式事务 (TransactionManager

4,事务隔离级别(和mysql一致)

未提交读
提交读
可重复读
串行化

5,事务的传播行为

PROPAGATION_REQUIRED(默认开启)
如果外部没有开启事务,则内部自己开启子事务
如果外部开启事务,则内部和外部属于同一个事务
PROPAGATION_REQUIRES_NEW
不论外部有没有开启事务,则内部自己都开启子事务
如果当前已存在事务,则直接挂起
PROPAGATION_NESTED
外部未开启事务,和require一样
外部开启事务,则内部方法变成子事务,可以一起回滚,内部的子事务可以独立回滚
PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

6,代码实现

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 配置事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知的规则 -->
<tx:advice id="myadvice" transaction-manager="transactionManager">
<tx:attributes> <!-- 配置事务的传播特性 -->
<tx:method name="change*" propagation="REQUIRED"/> <!-- change开头,添加事务,传播特性为:REQUIRED -->
<tx:method name="find*" read-only="true"/> <!-- find开头的方法只读,不能修改数据 -->
<tx:method name="userLogin" read-only="true"/>
</tx:attributes>
</tx:advice>

八、注解:

添加xsd->添加<context:annotation-config/>
->添加<context:component-scan base-package="*"/>
->简单整合hibernate并使用hibernateTemplate做增删改查工具
->介绍@Component@Resourece@Autowired 实现IOC功能
-><aop:aspectj-autoproxy></aop:aspectj-autoproxy>开启AOP的注解模式

九、与设计模式的联系:

Spring 中的单例模式:
创建bean为单例时
Spring 中的代理模式:
Spring 中的AOP 是代理模式的应用,有静态代理跟动态代理
Spring 中的工厂模式:
Spring中在各种BeanFactory以及ApplicationContext创建中都用到了典型的工厂方法模式

十、配置文件(标签):

tx通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
">

<!-- 要使用spring注解需要引入context文档规范 -->
<context:annotation-config/> <!-- 这句话用来开启spring的注解模式 -->
<!-- 指定包中的类头上带有特定的注解:@Component,@Repository,@Service,@Controller,
就会将这个对象作为Bean注册进spring容器。自动注册 -->
<context:component-scan base-package="*"/>

<!-- @@@@@@@ mybatis&spring连接池配置 @@@@@@ -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&amp;allowMultiQueries=true"></property>
<property name="username" value="root"></property>
<property name="password" value="2936283"></property>
</bean>
<!-- 配置基本mybatis -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- dataSource属性指定要用的连接池 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 将对应mapper的xml文件都配置到这里 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
<!-- 将对应entity的java文件都配置到这里 -->
<property name="typeAliasesPackage" value="entity"></property>
</bean>
<!-- 配置dao接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="dao"></property>
</bean>

<!-- 配置事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>


<!-- 配置事务通知的规则 -->
<tx:advice id="myadvice" transaction-manager="transactionManager">
<tx:attributes> <!-- 配置事务的传播特性 -->
<tx:method name="change*" propagation="REQUIRED"/> <!-- change开头,添加事务,传播特性为:REQUIRED -->
<tx:method name="find*" read-only="true"/> <!-- find开头的方法只读,不能修改数据 -->
<tx:method name="userLogin" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置切入 -->
<aop:config>
<aop:pointcut expression="execution(* service.*.*(..))" id="mypc"/>
<!-- 引用tx通知,引用切线mypc -->
<aop:advisor advice-ref="myadvice" pointcut-ref="mypc"/>
</aop:config>
</beans>

aop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 要使用spring注解需要引入context文档规范 -->
<context:annotation-config/> <!-- 这句话用来开启spring的注解模式 -->
<!-- 指定包中的类头上带有特定的注解:@Component,@Repository,@Service,@Controller,
就会将这个对象作为Bean注册进spring容器。自动注册 -->
<context:component-scan base-package="*"/>


<aop:config>
<!-- 配置切点。这里有个表达式:execution表达式,用来配置往哪切入 -->
<aop:pointcut expression="execution(* service.UserService.userLogin(..))" id="mypc"/>
<aop:pointcut expression="execution(* service.UserService.userRegister(..))" id="mypc1"/>
<aop:pointcut expression="execution(* service.UserService.user*(..))" id="mypc2"/>
<aop:pointcut expression="execution(* service.UserService.*(..))" id="mypc3"/>
<aop:pointcut expression="execution(* service.*.*(..))" id="mypc4"/>
<!-- 配置切入的方向 ,即切面-->
<aop:aspect ref="madvice">
<!-- 前置通知 -->
<aop:before method="beforelog" pointcut-ref="mypc"/>

<!-- 后置通知 -->
<aop:after method="afterlog" pointcut-ref="mypc"/>

<!-- 环绕通知 -->
<!-- <aop:around method="aroundlog" pointcut-ref="mypc"/> -->

<!--异常通知 -->
<!-- <aop:after-throwing method="throwlog" throwing="e" pointcut-ref="mypc"/> -->

<!-- <aop:after-throwing method="throwlog" pointcut-ref="mypc1"/> -->
</aop:aspect>

<aop:aspect ref="padvice">
<!-- 返回通知:可以获取返回值 -->
<!-- <aop:after-returning method="afterReturn" returning="retValue" pointcut-ref="mypc"/> -->
</aop:aspect>
</aop:config>
</beans>

Spring期末复习
https://moechun.fun/2021/12/19/Spring期末复习/
作者
Knight Kilito
发布于
2021年12月19日
更新于
2023年3月23日
许可协议