这一段纯属废话,可以不用看........,兑现诺言,每周写一篇博客。最近除了学习算法,还有想更全面了解Spring框架的使用。于是开始了我的学习之旅。由于本人工作中接触的是一个非常非常老的项目,所以对Spring的了解仅仅停留在一些基本的使用上。为加深了解Spring提供的功能,于是就果断买了《Spring实战》,初略看下来,收获还是有的,但总感觉也不是特别特别优秀的书。接下来,我就来谈谈我对Spring的一点浅薄理解。
一、Spring第一印象
对于Java后端开发来说,Spring基本是再熟悉不过的框架了,甚至可以说,现在不用Spring框架进行开发的JAVA后端项目应该基本是凤毛麟角(个人猜测)。相信一提到Spring,大家想到的就是DI(Dependency Injection)/IOC(Inversion of Control)、AOP这些名词了,没错,这就是Spring提供的核心功能。DI、IOC说的就是同一个功能,翻译过来分别是依赖注入、控制反转,其实就是我们把对象的创建、销毁、维护交给Spring,让它帮我们管理这些对象,但我们需要的时候,让它直接给我们一个,不需要我们自己去new。AOP就是面向切面编程。额额,看着这些名词一脸懵逼.................................
接下来就来个小例子看看这到底能干嘛,能给我们编程提供什么样的帮助。。
在给小例子之前我们得先了解两个概念:
1、既然要让Spring帮我们创建管理对象、那我们就得先告诉Spring怎么去创建这些对象,还有对象之间是什么关系。Spring提供了3个方案来实现:1、XML中显式配置。2、Java中显式配置。3、自动包扫描
2、Spring提供了俩种容器类型,分别为BeanFactory、ApplicationContext。BeanFactory只提供了基本的DI支持,ApplicationContext基于BeanFactory构建,能提供更多服务。
Spring上下文,就是一种容器,继承自ApplicationContext,提供更多功能,如常见的,
AnnotationConfigApplicationContext可从JAVA配置类中加载上下文
ClassPathXmlApplicationContext 从类路径下的XML文件中加载上下文。
FileSystemXmlApplilcationContext 从文件系统路径中加载上下文
例子
接下来我们用Idea编辑器,通过maven工具创建一个maven项目来体验下Spring。创建完之后我们首先要引入Spring jar包,通过maven,我们不需要自己去下载,只需要在配置文件中配置我们需要用到的jar包。项目结构如下图
之后我们在pom.xml文件中配置需要用到的jar文件,我们将spring的几个核心包配置进来。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.springstudy</groupId>
<artifactId>luckyspring</artifactId>
<version>1.0-SNAPSHOT</version>
<name>luckyspring</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<!-- spring 版本 -->
<org.springframework.version>4.0.0.RELEASE</org.springframework.version>
</properties>
<dependencies>
<!-- 当前项目用到的3个核心spring jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
复制代码
现在假设我们有一个公司,一个公司里面得有雇员来工作,才能让公司提供服务,于是我们创建雇员类
package cn.springstudy.vo;
public class Employee {
public void work(){
System.out.println("Employ start to Work");
};
}复制代码
再创建公司类
package cn.springstudy.vo;
public class Company {
//公司类有个雇员对象
private Employee employee;
public void supportService(){
employee.work();
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}复制代码
前面我们说过告诉Spring怎么去创建对象有三种方式
方式一XML配置来告诉spring怎么去创建我们的雇员还有公司类,在创建一个applicationContext.xml文件,内容如下
<?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">
<!-- 配置一个对象 指定该对象id为emplayee-->
<bean id="employee" class="cn.springstudy.vo.Employee"></bean>
<!--配置对象,之后往对象中放入一个Employee对象
ref="employee"表示注入的对象为spring容器中id为employee的对象,这样配置后创建Company
对象后,会自动调用setEmployee()方法放入一个Employee对象
-->
<bean id="company" class="cn.springstudy.vo.Company">
<property name="employee" ref="employee"></property>
</bean>
</beans>复制代码
接下来我们创建一个main函数作为程序的入口,在main函数中去创建Spring容器
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringStudy {
public static void main(String arg[]){
//方式一,XML文件中加载上下文,即Spring容器
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取一个Company对象
Company company = (Company) classPathXmlApplicationContext.getBean("company");
company.supportService();
}
}复制代码
执行一下,控制台打印如下
我们可以看到我们执行company.supportService()居然没报空指针,要知道我们可没在Company类中去创建Empoyee对象,说明什么???Spring容器自动帮我们创建Employee对象并set到Company对象中了。
方式二
创建一个配置Java类
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import cn.springstudy.vo.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//注解,表明这个是一个Spring配置类
@Configuration
public class SpringConfig {
//Spring容器管理的类,通过Bean注解,方法名即默认为bean的id,也可在Bean注解后加参数指定Bean的ID
@Bean
public Employee employee(){
return new Employee();
}
//Spring容器管理的类,通过Bean注解
@Bean
public Company company(){
Company company = new Company();
company.setEmployee(employee());
return company;
}
}
复制代码
main函数,程序入口,执行结果同上
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringStudy {
public static void main(String arg[]){
//方式二,默认bean的名称即为配置方法的名称,需要用到AnnotationConfigApplicationContext容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(SpringConfig.class);
annotationConfigApplicationContext.refresh();
Company company1 = (Company) annotationConfigApplicationContext.getBean("company");
company1.supportService();
}
}复制代码
方式三、
方式三序借助方式一或者方式二,我们首先需要在需要被Spring容器管理的类上面加上@Component注解,所以我们在Empoyee加上注解
package cn.springstudy.vo;
import org.springframework.stereotype.Component;
@Component
public class Employee {
public void work(){
System.out.println("Employ start to Work");
};
}复制代码
Company类上加上注解,需自动分配的对象上加@Autowired注解
package cn.springstudy.vo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Company {
//Autowired,帮我分配个Employee对象过来。
@Autowired
private Employee employee;
public void supportService(){
employee.work();
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}复制代码
在配置类上加上包自动扫描路径
package cn.springstudy.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//cn.springstudy.vo 为扫描的基础包路径
@Configuration
@ComponentScan("cn.springstudy.vo")
public class SpringConfigScan {
}复制代码
测试main方法
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringStudy {
public static void main(String arg[]){
//方式三,需借助方式2
AnnotationConfigApplicationContext annotationConfigApplicationContext2 = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext2.register(SpringConfig.class);
annotationConfigApplicationContext2.refresh();
Company company2 = (Company) annotationConfigApplicationContext.getBean("company");
company2.supportService();
}
}复制代码
执行结果同上。
XML、Java配置文件混着使用
当然XML配置方式和Java配置文件还能混着用。
1、在XML配置中混用Java配置文件只需在配置文件中增加一个<bean></bea>即可将Java配置类导入XML配置中。2、XML中导入其他XML配置,只需用<import>指定其他XML配置文件路径
<?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">
<!--导入其他XML配置文件 -->
<import resource="applicationContext2.xml"></import>
<!--Spring Java配置类-->
<bean class="cn.springstudy.spring.SpringConfig"></bean>
<bean id="employee" class="cn.springstudy.vo.Employee"></bean>
<bean id="company" class="cn.springstudy.vo.Company">
<property name="employee" ref="employee"></property>
</bean>
</beans>复制代码
1、Java配置文件混着XML配置文件,只需在Java类中加个注解即可,2、Java配置类导入其他配置类,只需加@Import注解,指定配置类位置。
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import cn.springstudy.vo.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
//导入其他XML配置文件
@ImportResource("classpath:applicationContext.xml")
//导入其他配置类
@Import({SpringConfigScan.class})
public class SpringConfig {
@Bean
public Employee employee(){
return new Employee();
}
@Bean
public Company company(){
Company company = new Company();
company.setEmployee(employee());
return company;
}
}复制代码
Spring DI初步使用方法已经如上,接下来我们主要通过XML配置的方式来说明其他功能。
构造方法注入依赖对象
以上的小例子中Company中的Employee对象是通过setEmployee方法配置进去的。我们还可以通过构造方法的形式配置进去。
给Company类增加一个构造方法
package cn.springstudy.vo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
public class Company {
private Employee employee;
private String name;
public Company(Employee employee,String name){
this.employee = employee;
this.name = name;
}
public void supportService(){
employee.work();
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}复制代码
配置文件配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/c
http://www.springframework.org/schema/c/spring-c.xsd">
<!--在上面beans中声明spring中c命名空间-->
<bean id="employee" class="cn.springstudy.vo.Employee"></bean>
<!-- 构造方法中注入Employee对象,还有一个名称其中
c:为命名空间前缀
emplayee、name分别为构造函数中参数的名称
-ref表示注入的是spring容器中的对象
"emplayee"表示引入的是id为emplayee的对象,name没有带-ref则是注入字符串juejin.com
-->
<bean id="company" class="cn.springstudy.vo.Company"
c:employee-ref="employee"
c:name="juejin.com">
</bean>
</beans>复制代码
工厂方法模式创建对象
以上说明Spring的依赖注入的基本使用。我们在编程时候可能不是通过new来创建对象,有时也会使用静态方法(静态工厂模式)来创建对象,那么Spring是否支持呢?答案是肯定的。
public class ClientService {
private ClientService() {}
public static ClientService createInstance() {
return new ClientService()
}
}复制代码
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>复制代码
当然工厂方法模式是通过非通过静态方法创建对象的,Spring也是支持的,如下
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}复制代码
<!-- 工厂类 -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
</bean>
<!-- ClientService类配置 -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>复制代码
Spring中bean的作用域
默认情况下,Spring容器中的bean都是单例的,可以通过配置修改。spring定义了多种作用域:
1、Singleton(默认) 单例
2、Prototype 原型,每次通过容器获取对象都会创建一个新对象、
3、Session 会话,一个web会话中使用一个对象
4、Request ,每次web请求使用一个对象
通过XML配置可在bean中指定scrop属性指定,
Java配置类可在方法上加注解@Scope("prototype")
自动扫描的类可在类上加注解@Scope("prototype")
<!-- scope 属性指定作用域 -->
<bean id="employee" class="cn.springstudy.vo.Employee" scope="prototype"></bean>复制代码
@Component
@Scope("prototype")
public class Company {.....}复制代码
@Configuration
public class SpringConfig {
@Bean
@Scope("prototype")
public Employee employee(){
return new Employee();
}
}复制代码
最后,感觉这篇写得有点乱,也很基础,还有很多东西没说到,不知道看到这里的人儿有无收获,说好的一周一篇,额,那就先发出来吧,以后可能还做修改,待续。。