文章目录
一、概念
- 1、控制反转(Inversion of Control)---->由用户管理Bean转变为框架管理Bean。不是什么技术,而是一种设计思想。
- 2、IOC Container:Spring框架托管创建的Bean存放地
- 3、XML配置,Java配置,注解配置:引入不同方式俩配置Bean,为了让用户更好的配置Bean
- 4、Spring框架既然接管了Bean的生成,必然需要管理整个Bean的生命周期等
- 5、依赖注入(Dependency Injection,DI):应用程序代码从IOC Container中获取依赖的Bean,注入到应用程序中
组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
- 6、Spring Bean
Spring里面的bean就类似是定义的一个组件,而这个组件的作用就是实现某个功能的,这里所定义的bean就相当于给了你一个更为简便的方法来调用这个组件去实现你要完成的功能。
谁控制谁,控制什么
传统JavaSE程序设计中,我们直接在对象内部通过new进行创建对象,是程序主动去创建对象;而IOC是有专门的一个容器来创建这些对象,即由容器来控制对象的创建;
IOC控制了对象
主要控制了外部资源(不只是对象包括文件等)
为何是反转,哪些方面反转
传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,这是正转
反转则是由容器来帮忙创建及注入依赖对象
原因:由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象
反转方面:依赖对象的获取被反转了
IOC的作用
传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
IOC与DI的关系
控制反转是通过依赖注入实现的,IOC是设计思想,DI是实现方式
二、Ioc 配置的三种方式
1、XML配置
将bean的信息配置.xml文件里,通过Spring加载文件为我们创建bean。这种方式出现很多早前的SSM项目中,将第三方类库或者一些配置工具类都以这种方式进行配置,主要原因是由于第三方类不支持Spring注解。
- 优点:可以使用于任何场景,结构清晰,通俗易懂
- 缺点:配置繁琐,不易维护,枯燥无味,扩展性查
example:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- services -->
<bean id="userService" class="tech.pdai.springframework.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
2、Java配置
将类的创建交给我们配置的JavaConfig类来完成,Spring只负责维护和管理,采用纯Java创建方式。其本质上就是把在XML上的配置声明转移到Java配置类中
- 优点:适用于任何场景,配置方便,因为是纯Java代码,扩展性高,十分灵活
- 缺点:由于是采用Java类的方式,声明不明显,如果大量配置,可读性比较差
1、创建一个配置类, 添加@Configuration注解声明为配置类
2、创建方法,方法上加上@bean,该方法用于创建实例并返回,该实例创建后会交给spring管理,方法名建议与实例名相同(首字母小写)。注:实例类不需要加任何注解
/**
* @author wk
*/
@Configuration
public class BeansConfig {
/**
* @return user dao
*/
@Bean("userDao")
public UserDaoImpl userDao() {
return new UserDaoImpl();
}
/**
* @return user service
*/
@Bean("userService")
public UserServiceImpl userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao());
return userService;
}
}
3、注解配置
通过在类上加注解的方式,来声明一个类交给Spring管理,Spring会自动扫描带有@Component
,@controller
,@Service
,@Repository
这四个注解的类,然后帮我们创建并管理,前提是需要先配置Spring的注解扫描器
- 优点:开发便捷,通俗易懂,方便维护
- 缺点:具有局限性,对于一些第三方资源,无法添加注解。只能采用XML或JavaConfig的方式配置
1、对类添加@Component相关的注解,比如@Controller
,@Service
,@Repository
2、设置ComponentScan的basePackage, 比如<context:component-scan base-package='com.wk.springframework'>
, 或者@ComponentScan("com.wk.springframework")
注解,或者 new AnnotationConfigApplicationContext("tech.pdai.springframework")
指定扫描的basePackage.
/**
* @author wk
*/
@Service
public class UserServiceImpl {
/**
* user dao impl.
*/
@Autowired
private UserDaoImpl userDao;
/**
* find user list.
*
* @return user list
*/
public List<User> findUserList() {
return userDao.findUserList();
}
}
三、依赖注入的三种方式
为什么推荐构造器注入方式
构造器注入的方式能够保证注入的组件不可变,并且确保需要的依赖不为空。此外,构造器注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。
- 依赖不可变:就是final关键字。
- 依赖不为空(省去了我们对其检查):当要实例化UserServiceImpl的时候,由于自己实现了有参数的构造函数,所以不会调用默认构造函数,那么就需要Spring容器传入所需要的参数,所以就两种情况:1、有该类型的参数->传入,OK 。2:无该类型的参数->报错。
- 完全初始化的状态:这个可以跟上面的依赖不为空结合起来,向构造器传参之前,要确保注入的内容不为空,那么肯定要调用依赖组件的构造方法完成实例化。而在Java类加载实例化的过程中,构造方法是最后一步(之前如果有父类先初始化父类,然后自己的成员变量,最后才是构造方法),所以返回来的都是初始化之后的状态。
/**
* @author wk
*/
@Service
public class UserServiceImpl {
/**
* user dao impl.
*/
private final UserDaoImpl userDao;
/**
* init.
* @param userDaoImpl user dao impl
*/
public UserServiceImpl(final UserDaoImpl userDaoImpl) {
this.userDao = userDaoImpl;
}
}
- 如果使用setter注入,缺点显而易见,对于IOC容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。而且将一直是个潜在的隐患,因为你不调用将一直无法发现NPE的存在。
四、@Autowired和@Resource以及@Inject等注解注入有何区别?
@Autowired
- 1、@Autowired是Spring自带的注解,通过AutowiredAnnotationBeanPostProcessor 类实现的依赖注入
- 2、@Autowired可以作用在CONSTRUCTOR、METHOD、PARAMETER、FIELD、ANNOTATION_TYPE
- 3、@Autowired默认是根据类型(byType )进行自动装配的
- 4、如果有多个类型一样的Bean候选者,需要指定按照名称(byName )进行装配,则需要配合@Qualifier。
指定名称后,如果Spring IOC容器中没有对应的组件bean抛出NoSuchBeanDefinitionException。也可以将@Autowired中required配置为false,如果配置为false之后,当没有找到相应bean的时候,系统不会抛异常
@Resource
- 1、@Resource是JSR250规范的实现,在javax.annotation包下
- 2、@Resource可以作用TYPE、FIELD、METHOD上
-3、@Resource是默认根据属性名称进行自动装配的,如果有多个类型一样的Bean候选者,则可以通过name进行指定进行注入
@Inject
- 1、@Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject jar包 ,才能实现注入
- 2、@Inject可以作用CONSTRUCTOR、METHOD、FIELD上
- 3、@Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named;
总结
- 1、@Autowired是Spring自带的,@Resource是JSR250规范实现的,@Inject是JSR330规范实现的
- 2、@Autowired、@Inject用法基本一样,不同的是@Inject没有required属性
- 3、@Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的
- 4、@Autowired如果需要按照名称匹配需要和@Qualifier一起使用,@Inject和@Named一起使用,@Resource则通过name进行指定