spring底层原理:XML、工厂模式和反射。
spring两大核心:IOC和AOP
IOC(Inversion of Control)思想基于IOC容器完成,IOC容器底层就是对象工厂。
spring提供IOC容器的两种实现方式:
1.beanFactory:这是IOC基本实现,是spring的内部的使用接口—类似于懒汉式加载
2.ApplicaitonContext:这是beanFactory的子接口,功能更强大,开发用—类似于饿汉式加载
ApplicaitonContext的实现类:
1.ClassPathXmlApplicationContext–读取 src 目录下的配置文件
2.FileSystemXmlApplicationContext–即系统文件路径,文件的目录
IOC操作 中的 bean管理
什么是bean管理:
- spring创建对象。
- spring注入属性
bean管理操作的两种方式:----创建对象,注入属性的方式
1. 基于xml配置文件实现
2. 基于注解方式实现
-
基于xml配置文件实现
创建对象,如:<bean id = "dao" class = "com.laowang.UserDao"></bean>
id属性:获取对象的唯一标识
class属性:类全路径
创建的时候也会执行默认的构造方法 -
基于注解方式实现
DI:依赖注入,就是注入属性
第一种注入方式:使用set方法进行注入
1.创建类,定义其属性和set方法
2.在spring配置文件配置对象创建,配置属性注入
第二章注入方式:使用有参数构造进行注入1. 创建类,定义属性,创建属性对应有参构造方法
<bean id = "", name = "">
<property name="bname" value="飘"> </property>
<property name="bauthor" value="玛格丽特·米切尔"></property>
</bean>
2. 在spring配置文件中
<bean id = "", name = "">
<constructor-arg name="bname" value="飘"></constructor-arg>
<constructor-arg name="bauthor" value="玛格丽特·米切尔"></constructor-arg>
<!--constructor-arg index = "0" value="玛格丽特·米切尔"--><!--/constructor-arg-->
</bean>
1 IOC操作bean管理----xml注入其他属性
- 字面量
(1) 空值:<property name="bname" ><null/></property>
(2) 属性包含特殊符号:<property name="bname" value="<<南京>>"></property>
解决方法:转义< >
把带特殊符号内容写入CDATA里<value><![CDATA[你的内容]]></value>
2 注入属性-外部bean
<bean id = "userService", class= "com.laowang.springoo.service.UserService">
<property name="userDao" ref="userDaoImpl"> </property> <!--用ref来注入-->
</bean>
3 注入属性-内部bean和级联赋值
<bean id = "emp", class= "com.laowang.springoo.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="esex" value="男"></property>
<property name="dept">
<bean id = "dept", class= "com.laowang.springoo.bean.Dept">
<property name="dname" ref="保安部"></property>
</bean>
</property>
</bean>
IOC操作bean管理–xml注入集合属性
1. 注入数组类型属性
<property name="list">
<array><value>张三</value><value>张三</value></array>
</property>
2. 注入list类型属性
<property name="list">
<list><value>张三</value><value>张三</value></list>
</property>
3. 注入map类型属性
<property name="list">
<map><entry key="张三" value="zhangsan"></entry>
<entry key="张三" value="zhangsan"></entry></map>
</property>
IOC操作bean管理—FactoryBean
spring里面有两种bean,一种普通bean,一种工厂bean
- 普通bena定义的类型就是返回的类型
- 工厂bean定义的类型可以和返回类型不一致
spring bean默认是单实例
- 在spring配置文件bean标签里scope属性用于设置单实例还是多实例
- scope属性值
第一种 默认是 singleton:当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把 一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的对象实例
<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>
第二种 **prototype** 多实例对象:prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。
<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>
–
第三种 request :request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
第四个 session : session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。
bean生命周期----也就是执行顺序
1. 通过构造器创建bean实例(无参数构造)
2. 为bean的属性设置值和对其他bean引用(调用set方法)
bean实例传递bean后置处理器的方法—postprocessbeforeInitialization
3. 调用bean的初始化的方法(配置)
bean实例传递bean后置处理器的方法—postprocessafterInitialization
4. bean可以获取—获取实例对象
5. 当容器关闭的时候,调用bean的销毁方法(需要配置销毁的方法)
IOC操作bean管理—xml自动装配
- 自动装配:根据指定装配规则(属性名或者属性类型),spring自动将配置的属性值进行注入
<bean id = "" class = "" autowire = "byName"></bean><bean id = "" class = "" autowire = "byType"></bean>
byName 根据属性名称注入,注入值bena的id值和类属性名称一样
byType 根据属性类型注入
xml装配用的很少
IOC操作bean管理(外部属性文件)
- 直接配置数据库信息
配置德鲁伊连接池
<bean id = "dataSource" class = "com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName",value="com.mysql.jdbc.driver"></property>
<property name="url",value="http://xxxx.xxxx.xxxx.xxx:3306/userDB"></property>
<property name="username",value="xxx"></property>
<property name="password",value="xxx"></property>
</bean>
- 引入外部属性文件配置数据库连接池
1 创建外部配置文件properties,写好驱动url,name,password
2 把外部的properties属性文件引入到spring配置文件中
引入context名称空间 xmlns:context
引入外部属性文件jdbc.properties
<context:property-placeholder location="classpath:hdbc.properties"/>
<bean id = "dataSource" class = "com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName",value="${prop.driverClass}"></property>
<property name="url",value="${prop.url}"></property>
<property name="username",value="${prop.userName}"></property>
<property name="password",value="${prop.password}"></property>
</bean>
IOC操作bean管理-----基于注解方式
-
什么是注解
1 注解是代码特殊标记, 格式:@注解名称(属性名称=属性值。。。。)
2 使用注解,注解作用在类上面,方法上面,属性上面。
3 使用注解简化xml配置。 -
spring针对bean管理中创建对象提供四种注解
1 @Component
2 @Service
3 @Controller
4 @Repository
***上面的四个注解功能是一样的,都可以用来创建bean实例,只不过用不同的名称用来区分不同的业务逻辑。 -
基于注解方式实现对象创建
引入AOP依赖
开启组件扫描<context:component-scan base-package="com.laowang.spring.Service, com.laowang.spring.dao"></context:component-scan>
创建类,在类上面添加创建对象注解-----注解里value属性可以不写,默认就是类名称,首字母小写 -
基于注解方式实现属性注入
1 根据属性的类型进行自动装配–@Autowired
第一步:把service和dao对象创建,在service和dao类添加创建对象注解
第二部:在service注入dao对象,在service类田家庵dao类型属性,在属性上面使用注解
2 根据属性名称进行注入---------@Qualifier
这个注解和上面的autowired一起使用
3 根据类型或者名称都行---------@Resource
-----javax中的,不是spring中的
4 注入普通类型属性--------------@Value
-
完全注解开发
创建配置类代替xml文件–配置类用的是@Configuration注解,还有@ConfigurationScan(basePackages={"com.laowang"})
代替xml中的component-scan
同时测试类中的applicationContext用的是AnnotationConfigurationContext(SpringConfig.class)
AOP—概念-----面向切面编程
好处:对业务逻辑各部分隔离,降低耦合度;不通过修改源代码添加功能。
AOP底层原理
- AOP用的是动态代理
两种情况的动态代理
第一种 有接口情况,使用JDK动态代理
第二种 没有接口情况, 使用CGLIB动态代理
实现:通过java.lang.reflect.proxy
— 调用newProxyInstance(classLoader loader,类<?>[] interfaces, invocationHandler h)
方法三个参数:
第一个:类加载器 classLoader
第二个:增强方法所在的类,这个类实现的接口,支持多个接口
第三个:实现这个接口invocationHandler ,创建代理对象,写增强的方法
AOP术语
- 连接点
类里的那些方法可以被增强,这些方法就是连接点 - 切入点
实际被真正增强的方法 - 通知
实际增强的逻辑部分称为通知
通知有五种类型:前置通知,后置通知,环绕通知,异常通知,最终通知 - 切面
是动作----把通知应用到切入点过程
AOP操作
- spring框架一般基于AspectJ实现AOP操作
----什么是AspectJ:独立的AOP框架,只不过一半和spring一起使用,进行AOP操作 - 基于AspectJ实现AOP操作
- 基于XML配置文件实现
- 基于注解方式实现
- 项目工程里引入AOP相关依赖 AspectJ
- 切入点表达式
- 切入点表达式的作用:知道对哪个类里的哪个方法进行增强
- 语法结构:
executioon([权限修饰符] [返回类型] [类全路径] [方法] ([参数列表]))
例子:对com.laowang.dao.BookDao类里的add进行增强
execution(*com.laowang.dao.BookDao.add(..))
例子:对com.laowang.dao.BookDao类里的所有方法进行增强
execution(*com.laowang.dao.BookDao.*(..))
例子:对com.laowang.dao包里的所有类里的所有方法进行增强
execution(*com.laowang.dao.*.*(..))
AOP操作—AspectJ注解
-
创建类,在类里定义方法
User -
创建增强类
1.在增强类里创建方法,让不同方法代理不同通知类型
UserProxy -
进行通知的配置
- 在spring配置文件中开启注解扫描-------xml配置注解扫描
- 使用注解创建User和UserProxy对象-----添加
@Component
- 在增强类中添加
@AspectJ
--------------生成代理对象 - 在spring配置文件中开启生成代理对象–
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
在spring配置文件中开启生成代理对象
-
公共切入点抽取—@PointCut注解抽取,想要被抽取的方法的
value="pointcut对应的方法"
-
有多个增强类对同一个方法进行增强,设置增强类优先级
— 增强类中添加注解@Order
,优先级越小越优先
AOP操作—AspectJ配置文件
- 创建两个类,增强类和增强方法
- 在spring配置文件中创建两个类对象
- 在spring配置文件中配置切入点
JdbcTemplate
spring对jdbc进行封装成了jdbctemplate
准备工作
- 引入jar包
- spring配置文件中配置数据库连接池
- 配置jdbctemplate,注入DataSource
编写service和dao层
dao层进行数据库添加操作
调用jdbctemplate进行增删改查
事务:逻辑上的一组操作,要么全部成功,要么全部不成功
事务四大特性 ACID 原子性-一致性-隔离性-持久性
spring中进行事务操作管理两种方式:编程式事务管理和声明式事务管理。
声明式事务管理----底层就是AOP
- 基于注解方式
- 基于xml配置文件方式
事务操作—声明式事务管理配置参数
-
在service类上面添加注解**@Transactional**,此注解中配置事务相关参数
-
配置propagation:事务传播行为
多事务方法直接进行调用,这个过程中事务是如何进行管理的
也就是 事务方法调用事务方法,非事务方法调用事务方法,事务方法调用非事务方法等
事务的传播行为分为7种****
1.REQUIRED:默认
如果add()方法本身有事务,调用了update方法后,update使用当前add方法的事务
如果add()方法本身没有事务,调用了update方法后,update创建新的事务
2.REQUIRED_NEW: 使用add方法调用update方法
无论add方法是否有事务,都创建新的事务
3.SUPPORTS:如果有事务在运行,当前方法就在这个事务运行,否则可以 不在事务中运行
4.NOT_SUPPORTED:当前的方法不应该运行在事务中,如果有运行的事务,挂起它
5.MANDATORY:当前方法必须运行在事务中,没有事务会抛异常
6.NEVER:和MANDATORY相反,当前方法不能运行在事务中,否则异常
7.NESTED:有事务运行的话,当前方法就应在这个事务的桥套事务内运行,否则启动一个新事务,在新事物内运行。 -
ioslation:事务隔离级别
1) 事务有隔离性,多事务操作之间不会有影响,不考虑隔离性会有三个问题。
2) 三个问题:**脏读,不可重复度,幻读**。
**脏读:一个未提交的事务读取到了另一个未提交事务的数据---加乐观锁
不可重复读:一个未提交的事务读取到了另一个已经修改过的数据(和自己读的不一样了)
幻读:一个未提交的事务读取到了另一个事务添加的数据**
3) 通过设置事务的隔离性解决三个问题:
设置隔离级别: 脏读 不可重复读 幻读
READ UNCOMMITTED 有 有 有
READ COMMITTED 无 有 有
REPEATABLE READ 无 无 有
SERIALIZATION 无 无 无
4) timeout:超时时间
事务需要在限定时间内提交,不提交就回滚
5) readOnly:是否只读
默认 false
6) rollbackFor:回滚
出现哪些异常会回滚
7) noRollBackFor:不回滚
出现哪些异常不回滚