spring框架:
1.spring是一个轻量级的控制反转和面向切面aop的容器框架
控制反转:ioc
核心容器:
1.应用上下文 context模块:
2.aop模块:
3.jdbc抽象和dao模块
4.对象关系映射集成模块
5.spring web模块
6.spring mvc框架
ioc:即控制反转,不是什么技术,而是一种设计思想,在JAVA开发中,ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制;在传统java se的程序设计,为们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而ioc是有专门的一个容器来创建这些对象,即由ioc容器来控制对象的创建;
反转:传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮助创建及注入依赖对象;因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;依赖对象的获取被反转了。
ioc能做什么:
ioc不是一种技术,只是一种思想。一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合,更优良的程序,传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了ioc容器后,吧创建和查找依赖对象的控制交给了容器;有容器进行诸如组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
ioc和di:
di-dependency injection 即 ‘依赖注入’ 组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态将某个依赖注入到组件之中,依赖注入的目的并非为软件系统带来更多功能,而是为提升组件重要的频率,并为系统搭建一个灵活,可扩展的平台,通过依赖注入机制,我们只需要通过简单的配置,而无需要任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关系具体的资源来自何处,由谁实现。
“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”
bean工厂:不是bean,在spring中一般指的是DefaultListableBeanFactory对象,管理和维护spring中所有的bean
工厂bean:一种特殊的bean,在xml文件中配置的,用来生成新的bean的加工厂,通过getObject()方法可以获取其生产的新bean,如果想获取该工厂bean本身,需要使用类似于getBean("&" + beanName)的样式。
<bean name="studentFactory" class="com.demo.StudentFactoryBean" />
1.构造方法注入:
2.setter注入:
3.基于注解的注入:
构造方法注入:
在spring的配置文件中注册UserService,将UserDaoJdbc通过constructor-arg标签注入到UserService的某个有参数的构造方法 <!-- 注册userService --> <bean id="userService" class="com.lyu.spring.service.impl.UserService"> <constructor-arg ref="userDaoJdbc"></constructor-arg> </bean> <!-- 注册jdbc实现的dao --> <bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>
通过name属性指定要注入的值,与构造方法参数列表参数的顺序无关。 <!-- 注册userService --> <bean id="userService" class="com.lyu.spring.service.impl.UserService"> <constructor-arg name="userDao" ref="userDaoJdbc"></constructor-arg> <constructor-arg name="user" ref="user"></constructor-arg> </bean> <!-- 注册实体User类,用于测试 --> <bean id="user" class="com.lyu.spring.entity.User"></bean> <!-- 注册jdbc实现的dao --> <bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>
基于注解的注入:
bean的一个属性autowire,autowire主要有三个属性值:constructor,byName,byType。
constructor:通过构造方法进行自动注入,spring会匹配与构造方法参数类型一致的bean进行注入,如果有一个多参数的构造方法,一个只有一个参数的构造方法,在容器中查找到多个匹配多参数构造方法的bean,那么spring会优先将bean注入到多参数的构造方法中。
byName:被注入bean的id名必须与set方法后半截匹配,并且id名称的第一个单词首字母必须小写,这一点与手动set注入有点不同。
byType:查找所有的set方法,将符合符合参数类型的bean注入。
注解方式注册bean,注入依赖
主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:
@Component:可以用于注册所有bean
@Repository:主要用于注册dao层的bean
@Controller:主要用于注册控制层的bean
@Service:主要用于注册服务层的bean
1.@Resource
2.@Autowired
@Resource java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。
@Resource @Qualifier("userDaoMyBatis") private IUserDao userDao; public UserService(){ }
@Autowired:spring注解,默认是以byType的方式去匹配类型相同的bean,如果只匹配到一个,那么就直接注入该bean,无论要注入的 bean 的 name 是什么;如果匹配到多个,就会调用 DefaultListableBeanFactory 的 determineAutowireCandidate 方法来决定具体注入哪个bean。determineAutowireCandidate 方法的内容如下:
determineAutowireCandidate 方法的逻辑是:
先找 Bean 上有@Primary 注解的,有则直接返回 bean 的 name。
再找 Bean 上有 @Order,@PriorityOrder 注解的,有则返回 bean 的 name。
最后再以名称匹配(ByName)的方式去查找相匹配的 bean。
可以简单的理解为先以 ByType 的方式去匹配,如果匹配到了多个再以 ByName 的方式去匹配,找到了对应的 bean 就去注入,没找到就抛出异常。
还有一点要注意:如果使用了 @Qualifier 注解,那么当自动装配匹配到多个 bean 的时候就不会进入 determineAutowireCandidate 方法(亲测),而是直接查找与 @Qualifer 指定的 bean name 相同的 bean 去注入,找到了就直接注入,没有找到则抛出异常。
tips:大家如果认真思考可能会发现 ByName 的注入方式和 @Qualifier 有点类似,都是在自动装配匹配到多个 bean 的时候,指定一个具体的 bean,那它们有什么不同呢?
ByName 的方式需要遍历,@Qualifier 直接一次定位。在匹配到多个 bean 的情况下,使用 @Qualifier 来指明具体装配的 bean 效率会更高一下。
1.调用构造器创建bean;
2.调用静态工厂方法创建bean;
3.调用实例工厂方法创建bean;
ioc底层原理:dom4j+反射
反射一定会走无参构造函数;
反射原理 加载配置xml配置文件,解析xml文件,bean的几点, 初始化bean id class=是全路径;
拿到beanid 去容器中
1.singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护;
2.prototype:原型范围与单例范围相反,为每一个bean请求提供一个实例;
3.request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会消失并被垃圾回收;
4.session:与请求范围类似,确保每一个session中有一个bean的实例,在session过期后,bean会随之失效;
5.global_session: global_session 和portlet应用相关,当你的应用部署在portlet容器中工作时,他包含很多portlet,如果你想要声明让所有的portlet公用全局的存储的话,那么这全局变量需要存储在global_session中。
1.springMVC的入口是servlet,而struts2是filter;
2.springmvc 会比struts2快些,springmvc是基于方法设计,而sturt2是基于类,每次发一次请求都会实例一个action;
3.springmvc 使用更加简洁,开发效率springmvc比struts2高;
spring并不是直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给hibernate或者jta等待持久化机制所提供的相关平台框架的事务来实现;
spring 事务: 1.编程式事务控制; jdbc代码 hibernate事务
声明事务:spring 声明式事务管理,核心实现就是基于aop
spring声明式是为管理类:
jdbc技术:DataSourceTransactionManager
Hibernate技术:HibernateTransationManager
spring session
web.xml 配置filter: springSessionRepositoryFilter
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
代理设计模式:通过代理控制对象的访问,可以想象访问某个对象方法,在这个方法调用处理,或者调用后处理,aop的核心技术面相切面编程;
@Aspect 指定一个类为切面类
@Pointcut("execution(* com.itmayiedu.service.UserService.add(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()")返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_(_()") 异常通知: 出现异常时候执行
@Around("poinrcut_()") 环绕通知:环绕目标方法执行
@before("execution(* com.muth.service.userservece.add(..))")