spring什么?优势是?
spring是轻量级的开源javaEE框架,可以解决企业级应用开发的复杂性
优势
① 方便解耦、简化开发
② aop支持,切面编程,代理对象
③ junit4支持方便单元测试
④ 方便和其他框架进行集成也可以单独使用
⑤ 降低javaApi的使用难度,对很多api进行封装
⑥ 声明式事务操作,方便事务管理
IOC底层原理
xml解析、反射、工厂模式
工厂模式解耦合
IOC结合工厂
IOC思想基于IOC容器完成,底层就是对象工厂
Spring提供IOC容器实现的两种方式(两个接口)
1、BeanFactory:IOC容器最基本的实现,一般spring内部使用
加载配置文件时并不会创建对象,在获取对象的时候才会创建对象。
2、ApplicationContext:是BeanFactory的子接口,提供更多强大的功能
加载配置文件的时候就会配置文件中的对象就会被创建
3、ApplicationContext中的实现类:
Bean作用域
spring中默认是单例,也可以设置多实例
通过属性 scope设置作用域
singleton 单实例对象,加载配置文件时就会创建对象
prototype 多实例原型,在getBean()时创建对象
request 一次请求
session 一次会话
Bean生命周期
① Userservice
② 推断构造方法 (通过@Autowired指定),默认无参,如果仅有多个有参构造且未指定,这会报错
③ 实例化对象
④ IOC属性注入(get set或者 构造方法),先ByType再ByName
④ 执行@PostContrct初始化前方法
⑤ 执行InitializingBean接口下afterPropertiesSet方法
⑥ 执行初始化后方法即AOP
⑦ 将AOP后的代理对象放入单例池
其中base-package为需要扫描的包(含所有子包)
1、@Service用于标注业务层组件
2、@Controller用于标注控制层组件(如struts中的action)
3、@Repository用于标注数据访问组件,即DAO组件.
4、@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Service public class UserServiceImpl implements UserService { }
@Repository public class UserDaoImpl implements UserDao { } getBean的默认名称是类名(头字母小写),如果想自定义,可以@Service(“***”) 这样来指定,这种bean默认是单例的,如果想改变,可以使用@Service(“beanName”)
@Scope(“prototype”)来改变。可以使用以下方式指定初始化方法和销毁方法(方法名任意): @PostConstruct public void init() { }
step1 扫描注解得到class 创建对象
spring通过注解扫描到类,然后通过反射:使用默认的无参构造函数进行实例化,当无参构造函数被覆盖,并且有多个构造函数的时候,可以使用**@Autowired**注解指定构造函数,得到一个普通对象
step2 依赖注入IOC 为属性设置
扫描这个类中的参数注解,从context上下文中getbean放到step1中实例化的对象中。byName或byType
注入方式:
①set注入
②有参构造函数
ref进行级联赋值
集合属性赋值:
spring中有两种 Bean和FactoryBean
Bean直接返回指定类对象
实现 FactoryBean 接口,可以返回指定类型,并实现以下三个方法
step3 初始化前方法
使用 @PostConstruct 标签来标记初始化前需要执行的方法,比如查询数据库数据
step4 初始化时接口
xml中init-method属性可以指定初始化方法
实现implements InitializingBean接口,实现afterPropertiesSet()方法,类似初始化前方法。
instance of
step5 初始化后AOP
基于后置处理器
会产生一个代理对象,真正放到单例池的是代理对象。
代理对象的属性还没有值,真正执行的时候属性是有值的。
普通对象是代理对象的一个属性
class UserServiceProxy extends UserService{
UserService target; // 将spring实例化的对象赋值给target
public void test(){
// 先执行切面 @Before 方法
// target.test()
// 再执行切面 @After方法
}
}
AOP实现事务
class UserServiceProxy extends UserService{
UserService target; // 将spring实例化的对象赋值给target
public void test(){
// 判断有 @Transactional注解
// conn.autocommit = false
// target.test() sql1 ,sql2
// 异常 conn.rollback() 正常conn.commit
}
}
当同一个类事务出现事务嵌套时,内部的事务不会生效,例:
原理:代理对象已经进入target普通对象的内部,只会执行这个普通对象的a()方法,不会再读取判断是否有@Transactional
class UserService{
@Transactional
public void test(){
//sql1
a();
}
@Transactional(propagation = Propagation.NEVER)
public void a(){
// sql2 sql3
}
}
解决方法:
①此时如果想实现 test()方法嵌套a() 则需要将a()方法写到另一个类中
②自己注入自己,例:
class UserService{
@Autowried
private UserService userService;
//自己注入自己,此时userService是一个完整的代理对象
//private UserService userService = (UserService )AopContext.currentProxy(); //也可以
@Transactional
public void test(){
//sql1
userService.a();
}
@Transactional(propagation = Propagation.NEVER)
public void a(){
// sql2 sql3
}
}
step6 当容器关闭时 调用销毁方法 销毁
context.close()关闭容器
如果是单例则需要放到单例池中,如果不是单例则直接返回
后置处理器 BeanPostProcessor
自动装配
autowire :byName 或者 byType(不能定义相同类型多个)
spring中七种事务的传播机制
spring在TransactionDefinition接口中定义了七个事务传播行为:
propagation-requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,则加入到这个事务中,这个是默认选项。
propagation-supports:如果当前有事务,则支持当前事务,如果当前没有事务,就以非事务方法执行。
propagation-mandatory:如果当前有事务,则使用当前的事务,如果没有当前事务,就抛出异常。
propagation-required_new:无论当前有没有事务,都要新建事务,如果当前存在事务,把当前事务挂起。
propagation-not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
propagation-never:以非事务方式执行操作,如果当前事务存在则抛出异常。
propagation-nested:如果当前存在事务,则作为子事务在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
spring中事务隔离级别
spring中的事务隔离级别
1、isolation_default 默认
使用数据库默认的事务隔离级别
2、isolation_read_uncommitted 读未提交
允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读
3、isolation_read_committed 读已提交
允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生
4、isolation_repeatable_read 可重复读
对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改。可防止脏读和不可重复读,但幻读仍有可能发生
5、isolation_serializable 序列化
完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。
spring三级缓存解决循环依赖
第一级缓存 单例池 singletonFactories
第二季缓存 早期对象 earlySingletonFactories
第三级缓存 原始对象或lamda表达式BeanDefinition