1.Spring核心
- IoC(Inverse of Control 控制反转): 将对象创建权利交给Spring工厂进行管理。 比如说 Book book = new Book();
现在: Book book = Spring工厂.getBook(); - AOP(Aspect Oriented Programming 面向切面编程),基于动态代理的功能增强方式。
2.IoC(Inverse of Control 控制反转)
Spring通过IoC的思想解决代码耦合问题。
简单的说就是引入工厂(第三者),将原来在程序中手动创建管理的依赖的UserDaoImpl对象,交给工厂来创建管理。
2.1 实现原理
在核心文件中配置bean标签,id属性为bean的名称,class属性指向要创建的对象类型的类字符串,Spring容器在启动后,就会通过bean的类字符串反射生成实例对象,存放到Spring容器中(工厂)
IoC底层实现:工厂(设计模式)+反射(机制) + 配置文件(xml)。
2.2 IoC容器装配Bean(基于注解)
2.2.1 Bean的定义(注册) – 扫描机制
-
xml做法 : ,用的方式创建对象
-
注解做法 : spring2.5引入
@Component
注解 如果放置到类的上面,相当于在spring容器中定义
当然仅仅在类上添加注解是不够的,我们还要让Spring容器能扫描到类,即开启注解扫描 <context:component-scan base-package="cn.itcast.spring"/>
实际开发中,使用的是@Component三个衍生注解(“子注解”)
- @Service用于标注业务层组件、(如Service层)
- @Controller用于标注控制层组件(如struts中的action层)
- @Repository用于标注数据访问组件,(如DAO层组件
3.Bean获取的两种方式
通过IoC我们可以将对象交给Spring工厂管理了
Spring工厂我们可以理解成如下,在一开始的时候会根据核心配置中bean的类字符串生成实例对象,然后以id:实例或者类型:实例存到工厂中,我们此时可以通过两种方式来获取实例
public classFactory {
public Object getBean(){
Object bean = null;
try {
//传入类字符串,生产对象实例
bean = Class.forName("cn.itcast.spring.a_quickstart.UserDAOImpl").newInstance();
} catch (Exception e) {
e.printStackTrace();
}
//返回具体类型的对象类型实例
return bean;
}
}
两种获取bean的方式
- 1.通过spring容器中bean的id/name获取 (常用)
- 2.根据bean的类型或者bean接口的类型获取,一般使用接口类型(如果根据类型获取,配置了多个类型的话,则抛出异常)
@Test
public void getBean(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean的两种方式
//1.通过spring容器中bean的id/name获取
//IUserService userService = (IUserService) ac.getBean("userService");
//2.根据bean的类型或者bean接口的类型获取,一般使用接口类型
IUserService userService = (IUserService) ac.getBean(IUserService.class);
userService.login();
}
4.实例化bean的4种方法
- 1.无参数构造器 (最常用)
<bean id =“bean1” class=“cn.itcast.spring.b_xmlnewbean.Bean1” /> - 2.静态工厂方法
<bean id = “bean2” class=“cn.itcast.spring.b_xmlnewbean.Bean2Factory” factory-method=“getBean2” /> - 3.实例工厂方法
<bean id=“bean3Factory” class=“cn.itcast.spring.b_xmlnewbean.Bean3Factory”/>
<bean id=“bean3” factory-bean=“bean3Factory” factory-method=“getBean3”/> - 4.FactoryBean方式。(源码底层用的多)
<!-- spring在实例化Bean4Factory的时候会判断是否实现了FactoryBean接口,如果实现了就调用getObject方法返回实例 -->
<bean id=“bean4” class=“cn.itcast.spring.b_xmlnewbean.Bean4Factory” />
5.DI注入
5.1 DI的实现
依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件(简单的说,可以将另外一个bean对象动态的注入到另外一个bean中。
DI的做法是:由Spring容器创建了Service、Dao对象,并且在配置中将Dao传入Servcie,那么Service对象就包含了Dao对象的引用。
那么如果并且在配置中将Dao传入Servcie?
我们只要在Service中定义属性提供setter方法,同事在配置中,通过property属性将引用指向Dao即可
public class UserServiceImpl implements IUserService{
// 定义属性
private IUserDAO userDAO;
public void setUserDAO(IUserDAO userDAO) {
this.userDAO = userDAO;
}
}
<bean id="userDAO" class="cn.itcast.spring.a_quickstart.UserDAOImpl" />
<bean id ="userService" class="cn.itcast.spring.a_quickstart.UserServiceImpl">
<property name="userDAO" ref="userDAO" />
</bean>
5.2 Bean属性的依赖注入(通过注解)
5.2.1 简单数据类型依赖注入
提供 @Value注解,可以完成简单数据的注入(不常用)
5.2.2 复杂类型数据依赖注入
(1) 使用@Value 结合SpEL
在属性声明上面注入,底层自动还是生成setCustomerDao()
@Value("#{customerDao}")
private CustomerDao customerDao;
(2) 使用@Autowired 结合 @Qualifier
单独使用@Autowired ,表示按照类型注入,会到spring容器中查找CustomerDao的类型,对应,class的属性值,如果找到,可以匹配。
使用@Autowired + @ Qualifier 表示按照名称注入,回到spring容器中查找customerDao的名称,对应,id的属性值,如果找到,可以匹配。
@Autowired//默认按照类型注入
private CustomerDao customerDao;
@Autowired//默认按照类型注入的
@Qualifier("customerDao")//必须配合@Autowired注解使用,根据名字注入
private CustomerDao customerDao;
(3) JSR-250标准(基于jdk) 提供注解@Resource
单独使用@Resource注解,表示先按照名称注入,会到spring容器中查找customerDao的名称,对应,id的属性值,如果找到,可以匹配。
如果没有找到,则会按照类型注入,会到spring容器中查找CustomerDao的类型,对应,class的属性值,如果找到,可以匹配,如果没有找到会抛出异常。
@Resource//默认先按照名称进行匹配,再按照类型进行匹配
private CustomerDao customerDao;
如果@Resource注解上添加name名称
使用@Resource注解,则按照名称注入,会到spring容器中查找customerDao的名称,对应,id的属性值,如果找到,可以匹配。
如果没有找到,抛出异常。
//第三种: JSR-250标准(jdk) 提供@Resource
@Resource(name="customerDao")//只能按照customerDao名称进行匹配
private CustomerDao customerDao;
(4) JSR-330标准(jdk) 提供 @Inject (麻烦点)
需要先导入 javax.inject 的 jar
//第四种: JSR-330标准(jdk) 提供 @Inject ,配合@name注解
@Inject//默认按照类型注入
private CustomerDao customerDao;
//第四种: JSR-330标准(jdk) 提供 @Inject ,配合@name注解
@Inject//默认按照类型注入
@Named("customerDao")//按照名字注入,必须配合@Inject使用
private CustomerDao customerDao;
6.Bean的作用域和生命周期
6.1 bean的作用域
- Singleton: 在一个spring容器中,对象只有一个实例。
(默认值)
Spring容器初始化时初始bean对象,只初始化一次 - Prototype: 在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例。
从spring中获取bean时初始化
6.2 bean的生命周期
通过spring工厂,可以控制bean的生命周期。
6.2.1 使用xml方式
- 通过 init-method属性 指定实例化后的调用方法
- 通过 destroy-method属性 指定销毁对象前的方法
6.2.2 使用注解方式
-
使用 @PostConstruct 注解, 标明初始化方法 —相当于 init-method 指定初始化方法
-
使用 @PreDestroy 注解, 标明销毁方法 ----相当于 destroy-method 指定对象销毁方法
6.3 后处理Bean(BeanPostProcessor接口)了解
后处理Bean也称之为Bean的后处理器,作用是:在Bean初始化的前后,对Bean对象进行增强。
它既可以增强一个指定的Bean,也可以增强所有的Bean
,底层很多功能(如AOP等)的实现都是基于它的,Spring可以在容器中直接识别调用。
7.Bean属性的依赖注入
什么是Bean属性的注入?就是对一个对象的属性赋值。有三种方式:
- 第一种:构造器参数注入 new Book(“金瓶梅”,15.8)
- 第二种:setter方法属性注入(setter方法的规范需要符合JavaBean规范)
第三种:接口注入
Spring 框架规范中通过配置文件配置的方式,只支持构造器参数注入和setter方法属性注入,不支持接口注入 !
8.AOP
AOP 思想: 基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码
,从而对原有业务方法进行增强 !
切面:需要代理一些方法和增强代码 。
Spring AOP编程两种方式
- Spring 1.2 开始支持AOP编程 (传统SpringAOP 编程),编程非常复杂 ---- 更好学习Spring内置传统AOP代码
- Spring 2.0 之后支持第三方 AOP框架(AspectJ ),实现另一种 AOP编程 – 推荐
8.1 AOP编程底层实现机制(了解)
AOP 就是要对目标进行代理对象的创建, Spring AOP是基于动态代理的,基于两种动态代理机制:JDK动态代理
和CGLIB动态代理
- JDK动态代理 : 针对
目标对象的接口
进行代理 ,动态生成接口的实现类 !(必须有接口)
- Cglib动态代理: Cglib的引入为了解决类的
直接代理问题(生成代理子类),不需要接口也可以代理 !
Spring AOP 优先对接口进行代理 (使用Jdk动态代理)
如果目标对象没有实现任何接口,才会对类进行代理 (使用cglib动态代理)
8.2 传统Spring AOP编程和AspectJ切面编程
传统Spring AOP编程看资料