maven3.6
jdk1.8
spring5.0.7
ide的话随便,创建maven项目即可
1.pom.xml
4.0.0
com.example
spring-demo1
0.0.1-SNAPSHOT
org.springframework
spring-beans
5.0.7.RELEASE
org.springframework
spring-core
5.0.7.RELEASE
org.springframework
spring-context
5.0.7.RELEASE
org.springframework
spring-expression
5.0.7.RELEASE
junit
junit
4.12
org.apache.maven.plugins
maven-compiler-plugin
3.2
1.8
UTF-8
2. 创建spring配置文件(resources路径下) -- applicationContext.xml
1. 思路
编写UserService接口的实现类
将UserService实现类交给Spring IoC容器管理
从Spring IoC容器中获取UserService实现类
2. UserService
public interface UserService {
void saveUser();
}
3. UserServiceImpl
public class UserServiceImpl implements UserService {
@Override
public void saveUser() {
System.out.println("IoC 演示 之UserService");
}
}
4. applicationContext.xml
5. 测试类TestSpringIoC.java
public class TestSpringIoC {
@Test
public void test1() {
// 创建ApplicationContext容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 方式1:根据Bean的类型,从容器中获取实例
UserService service1 = context.getBean(UserService.class);
// 方式2:根据bean的id从容器中获取bean的实例
UserService service2 = (UserService) context.getBean("userService");
service1.saveUser();
service2.saveUser();
}
}
bean标签作用:
用于配置对象让 spring 来创建的。
默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
bean标签属性:
id:给对象在容器中提供一个唯一标识。用于获取对象。
class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围。
* singleton :默认值,单例的(在整个容器中只有一个对象).
* prototype :多例的.
* request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
* session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
* global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.
init-method:指定类中的初始化方法名称。
destroy-method:指定类中销毁方法名称。比如DataSource的配置中一般需要指定destroy-method=“close”。
bean的作用范围:
单例对象:scope="singleton"
一个应用只有一个对象的实例。它的作用范围就是整个引用。
生命周期:
*对象出生:当应用加载,创建容器时,对象就被创建了。
*对象活着:只要容器在,对象一直活着。
*对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
多例对象:scope="prototype"
每次访问对象时,都会重新创建对象实例。
生命周期:
*对象出生:当使用对象时,创建新的对象实例。
*对象活着:只要对象在使用中,就一直活着。
*对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
1. 使用默认无参构造函数(重点)
在默认情况下:它会根据默认无参构造函数来创建类对象。
如果 bean 中没有默认无参构造函数,将会创建失败。
2. 静态工厂(了解)
/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
public static UserService createUserService(){
return new UserServiceImpl();
}
}
3. 实例工厂(了解)
/**
* 模拟一个实例工厂,创建业务层实现类
* 此工厂创建对象,必须现有工厂实例对象,再调用方法
*/
public class InstanceFactory {
public UserService createUserService(){
return new UserServiceImpl();
}
}
什么是依赖?
依赖指的就是Bean实例中的属性
属性分为:简单类型(8种基本类型和String类型)的属性、POJO类型的属性、集合数组类型的属性。
什么是依赖注入?
依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。
为什么要进行依赖注入?
我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。
ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
顾名思义,就是使用类中的构造函数,给成员变量赋值。
注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。
代码如下
public class UserServiceImpl implements UserService {
private int id;
private String name;
public UserServiceImpl(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public void saveUser() {
System.out.println("保存用户:id为" + id + ",name为" + name + " Service实现");
}
}
使用构造函数的方式,给 service 中的属性传值要求:类中需要提供一个对应参数列表的构造函数。
涉及的标签:constructor-arg
- index:指定参数在构造函数参数列表的索引位置
- name:指定参数在构造函数中的名称
- value:它能赋的值是基本数据类型和 String 类型
- ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
set方法注入又分为手动装配方式注入和自动装配方式注入。
- 手动装配方式(XML方式):bean标签的子标签property,需要在类中指定set方法。
- 自动装配方式(注解方式,后面讲解):@Autowired注解、@Resource注解。
@Autowired:一部分功能是查找实例,从spring容器中根据类型(java类)获取对应的实例。另一部分功能就是赋值,将找到的实例,装配给另一个实例的属性值。(注意事项:一个java类型在同一个spring容器中,只能有一个实例)
@Resource:一部分功能是查找实例,从spring容器中根据Bean的名称(bean标签的名称)获取对应的实例。另一部分功能就是赋值,将找到的实例,装配给另一个实例的属性值。
1. 步骤一:需要先引入 p 名称空间
* 在schema的名称空间中加入该行:xmlns:p="http://www.springframework.org/schema/p"2. 步骤二:使用p名称空间的语法
* p:属性名 = ""
* p:属性名-ref = ""3. 步骤三:测试
ref就是reference的缩写,是引用的意思。
1. 如果是数组或者List集合,注入配置文件的方式是一样的
//如果集合内是简单类型,使用value子标签,如果是POJO类型,则使用bean标签
美美
小风
2. 如果是Set集合,注入的配置文件方式如下
哈哈
呵呵
3. 如果是Map集合,注入的配置方式如下
4. 如果是Properties集合的方式,注入的配置如下
root
123
学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。
关于实际的开发中到底使用xml 还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌握。
我们在讲解注解配置时,采用上一节的案例,把 spring 的 xml 配置内容改为使用注解逐步实现。
//在需要被spring IoC容器管理的类上面加上组件注解
//value:指定该类在容器中的唯一标识,相当于bean标签的id
//默认的bean的id就是类名首字母小写,比如这个类的bean的id是userServiceImpl
@Component(value="userService")
public class UserServiceImpl implements UserService {
相当于:
1. @Component注解
作用:
把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
属性:
value:指定 bean 的 id。
如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。
2. @Controller、@Service、@Repository注解
他们三个注解都是针对@Component的衍生注解
他们的作用及属性都是一模一样的。他们只不过是提供了更加明确的语义化。
@Controller:一般用于表现层的注解。
@Service:一般用于业务层的注解。
@Repository:一般用于持久层的注解。
细节:如果注解中有且只有一个属性要赋值时,且名称是 value,value 在赋值是可以不写。
相当于:
1. @Autowired
默认按类型装配(byType)
这个注解是spring自身的
默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)
如果我们想使用名称装配可以结合@Qualifier注解进行使用
2. @Qualifier
在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。
它在给字段注入时不能独立使用,必须和@Autowire 一起使用;但是给方法参数注入时,可以独立使用。
3. @Resource
默认按照名称(byName)进行装配,名称可以通过name属性进行指定
这个注解属于J2EE的
如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,当找不到与名称匹配的bean时才按照类型进行装配。
但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。推荐使用@Resource注解,因为这个注解是属于J2EE的,减少了与spring的耦合。
4. @Value
给基本类型和String类型注入值
可以使用占位符获取属性文件中的值。
@Value(“${name}”) //name是properties文件中的key
private String name;
spring配置文件
data.properties
id=123
//简单类型的注入(配合properties文件使用)
@Value("${id}")
private int id;
1. @Scope
相当于
作用:
指定 bean 的作用范围。
属性:
value:指定范围的值。
取值:singleton prototype request session globalsession
相当于:
@PostConstruct和@PreDestroy
注解的优势:
配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
XML 的优势:
修改时,不用改源码。不涉及重新编译和部署。
- 介绍:
从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件
相当于根标签
配置类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
- 属性:
value:用于指定配置类的字节码
- 示例代码:
@Configuration public class SpringConfiguration { //spring容器初始化时,会调用配置类的无参构造函数 public SpringConfiguration(){ System.out.println(“容器启动初始化。。。”); } }
- 介绍:
@Bean标注在方法上(返回某个实例的方法),等价于spring配置文件中的
作用为:注册bean对象
主要用来配置非自定义的bean,比如DruidDataSource、SqlSessionFactory
- 属性:
name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)。
如果不指定,默认与标注的方法名相同
@Bean注解默认作用域为单例singleton作用域,可通过@Scope(“prototype”)设置为原型作用域;
- 示例代码:
@Configuration public class SpringConfiguration { //spring容器初始化时,会调用配置类的无参构造函数 public SpringConfiguration(){ System.out.println(“容器启动初始化。。。”); } @Bean @Scope(“prototype”) public UserService userService(){ return new UserServiceImpl(1,“张三”); } }
- 介绍:
相当于context:component-scan标签
组件扫描器,扫描@Component、@Controller、@Service、@Repository注解的类。
该注解是编写在类上面的,一般配合@Configuration注解一起使用。
- 属性:
basePackages:用于指定要扫描的包。
value:和basePackages作用一样。
- 示例代码:
Bean类(Service类):
@Service public class UserServiceImpl implements UserService { @Override public void saveUser() { System.out.println("保存用户 Service实现"); } }
配置类:
@Configuration @ComponentScan(basePackages="com.spring.service") public class SpringConfiguration { public SpringConfiguration() { System.out.println("容器初始化..."); } // @Bean // @Scope("prototype") // public UserService userService() { // return new UserServiceImpl(1,"张三"); // } }
- 介绍
加载properties配置文件
编写在类上面
相当于context:property-placeholder标签
- 属性
value[]:用于指定properties文件路径,如果在类路径下,需要写上classpath
配置类:
@Configuration
@PropertySource(“classpath:jdbc.properties”)
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 创建一个数据源,并存入 spring 容器中
*/
@Bean(name = "dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
properties文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=root
- 介绍
用来组合多个配置类
相当于spring配置文件中的import标签
在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问题。
- 属性
value:用来指定其他配置类的字节码文件
@Configuration
@ComponentScan(basePackages = "com.spring")
@Import({JdbcConfig.class})
public class SpringConfiguration {
}
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
}
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService service = context.getBean(UserService.class);
service.saveUser();
org.springframework.web.context. support.AnnotationConfigWebApplicationContext
com.spring.test.SpringConfiguration
org.springframework.web.context.ContextLoaderListener
|
分模块开发的场景描述:
表现层:spring配置文件,只想管理表现层的Bean
业务层:spring配置文件,只想管理业务层的Bean,并且进行事务控制
持久层:spring配置文件,只想管理持久层的Bean,并且还有需要管理数据源的Bean
为了方便管理项目中不同层的Bean对象,一般都是将一个spring配置文件,分解为多个spring配置文件。分解之后的spring配置文件如何一起被加载呢??
一种就是同时指定多个配置文件的地址一起加载
另一种就是:定义一个import.xml文件,通过import标签将其他多个spring配置文件导入到该文件中,tomcat启动时只需要加载import.xml就可以。