spring是一个从实际开发中抽取出来的框架,它完成了大量的通用步骤,留给开发者的仅仅是与特定应用相关的部分,从而大大提高了企业应用的开发效率。spring为企业应用的开发提供了一个轻量级的解决方案,该解决方案包括:IOC、AOP、与多种持久层技术的整合,以及优秀的Web MVC框架等。
spring可以把一切java对象当成容器中的bean,也就是说不管该java类是JDK的,还是第三方jar包的,亦或是开发者自己写的,只要是个java类,我们就可以把它配置在xml配置文件中或者给它配置相应注解或是用@Bean方式,从而利用spring容器来管理它。需要注意的是,JDK和第三方jar包的类只能在xml文件中配置或者用@Bean方式,因为在源码中加注解是不可能的嘛!
在spring配置文件中用<bean />配置bean时,class属性的值不能是接口和抽象类。
spring把对象调用关系称为依赖关系。假如A组件调用了B组件的方法,即可称A组件依赖B组件。使用spring框架之后,调用者无须主动获取被依赖对象,只须被动接受spring容器为调用者的成员变量赋值即可,这种方式称为控制反转(Inversion of Control,IoC,故spring容器也可以称为IoC容器)。从spring容器的角度看,spring容器负责将被依赖对象赋值给调用者的成员变量—相当于为调用者注入它依赖的实例,故也被称为依赖注入(Dependency Injection)。
依赖注入分为两种方式:
1.设值注入,也被称为属性注入:IoC容器使用成员变量的setter方法来注入被依赖对象,在<bean />元素中使用<property/ >子元素即可。
spring框架会通过反射的方式调用该类的无参构造器创建一个java对象,如果给<bean />元素配置了<property />子元素,则spring框架会以反射方式执行一次setter方法,<property />元素的name属性值决定执行哪个setter方法,value或ref属性值是执行setter方法时传入的参数,之后再以<bean />的id属性的值为key,将该对象放入spring容器中,这样这个java对象就成了spring容器中的bean。
2.构造注入:IoC容器使用构造器来注入被依赖对象,在<bean />元素中使用<constructor-arg />子元素。
此时spring容器在实例化bean的时候调用的不是无参构造器,而是包含指定参数的有参构造器,之后再以<bean />的id属性的值为key,将该对象放入spring容器中。这种方式要求在bean类中要声明对应的构造器,否则会报异常。
ApplicationContext(org.springframework.context.ApplicationContext,在spring-context-xxx.jar中)是表示spring容器最常用的接口,常用的实现类为ClassPathXmlApplicationContext。可以通过new实现类的方式手动创建spring容器:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
在web应用中,spring容器通常采用声明式方式配置产生,我们只需在web.xml文件中配置ContextLoaderListener(org.springframework.web.context.ContextLoaderListener,在spring-web-xxx.jar中),这样在web应用启动时自动创建spring容器。当 web应用创建spring容器时,默认会初始化所有的singleton bean,如果不想在创建spring容器时初始化某singleton bean,可以把该<bean />元素的lazy-init属性设为true,这样spring容器就会在系统用到该singleton bean时才创建并初始化该bean。
在web应用中可以通过调用ContextLoader类的getCurrentWebApplicationContext()方法得到spring容器:
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
对于singleton作用域的bean,每次客户端代码请求时都会返回同一个共享实例,spring容器负责跟踪bean实例的产生、销毁。
对于prototype作用域的bean,spring容器仅仅负责创建,当容器创建了bean实例之后,bean实例完全交给客户端代码管理,容器不再跟踪其生命周期。
spring的注解
spring提供了如下几个注解来标注bean类,在类的定义语句上面使用:
@Component:标注一个普通的bean类
@Controller:标注一个控制器组件类
@RestController:标注一个控制器组件类,从spring 4.0版本之后才有的注解,功能比@Controller强,等于@Controller+@ResponseBody,用了这个注解的话,controller中的接口就不用@ResponseBody标注了。
@Service:标注一个业务逻辑组件类
@Repository:标注一个Dao组件类
在用上面的注解标注某些类之后,还需要在spring的配置文件中配置<context:component-scan base-package="xxx" />来指定搜索目录,从而让spring容器在指定的目录下搜索标注了注解的类。
@Autowired、@Resource:标注成员变量,用于自动注入。
区别是:
@Autowired是spring提供的一个注解,根据type注入,后面()括号中只有一个required属性,只能选是否必须,其他无可奈何。
如在PrintController中有
@Autowired private PrintService printService;
则会把spring容器中的PrintService实例注入。假如spring容器中有多个PrintService实例(PrintService接口有多个实现类的情况),那么用@Autowired就会报错。阿里规约插件会提示:Could not autowire. There is more than one bean of 'PrintService' type。
@Resource是jdk自带的一个注解,根据名称注入,后面括号中有个name属性,可以选择spring容器中指定id的对象注入,特别适用于一个接口有多个实现类的情况。
假如PrintService有2个实现类,AutoPrintServiceImpl和ManualPrintServiceImple,如果想注入AutoPrintServiceImpl对应实例,则操作如下:
用@Service(value = "autoPrint")标注AutoPrintServiceImpl,即指定AutoPrintServiceImpl由spring实例化时id为autoPrint,用@Service(value = "manualPrint")标注manualPrintServiceImpl,即指定ManualPrintServiceImpl由spring实例化时id为manualPrint。同时,在PrintController中
@Resource(name = "autoPrint") private PrintService autoPrintService;
@Lazy:标注一个bean类,用来指定是否延迟初始化,用法:@Lazy(value = true),可选,默认是false。
@Bean:标注方法。这个方法的返回值会被放到spring容器中。方法可以有参数,但是参数必须也是spring容器中的实例。
@Configuration:标注类。这个类中至少有一个用@Bean标注的方法。但其实如果类中没有@Bean标注方法,用@Configuration标注也不会报错。
@InitBinder:标注方法。用法是