本文已参与「新人创作礼」活动,一起开启掘金创作之路。
spring引入
1.为什么要用spring?
- 简化开发---降低了大型项目开发的复杂型。
- 框架整合---高效整合其他技术,提高大型项目开发与运行效率。
Spring框架的足够灵活受到世界各地开发人员的信任。 无论是流媒体电视、在线购物、还是无数其他创新的解决方案,Spring每天都为数百万终端用户提供愉快的体验。 Spring也有来自所有科技巨头的贡献,包括阿里巴巴、亚马逊、谷歌、微软等。所以,尽情的畅用spring吧~
2.spring核心概念
IOC(Inversion of Control)控制反转
使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。通俗的讲就是“将new对象的权利交给Spring,我们从Spring中获取对象使用即可”
-
Spring技术对IoC思想进行了实现
- Spring提供了一个容器,称为IOC容器,用来充当IoC思想中的“外部”
- IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
-
DI(Dependency Injection)依赖注入
- 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。
3.IoC和注入依赖
需要关注和掌握的是:
- 如何把定义的类通过xml配置的方式放入IoC容器(Bean)
- 如何从容器中取出想要的Bean
- 当A对B产生依赖,在xml中如何表示这个关系 这个部分的知识点,博主就借用之前写的文章来讲解了,《spring之xml配置文件开发》juejin.cn/post/710119… 这篇文章IoC那部分博主写了一个BookDao接口以及它对实现类,然后在xml中写了这个实现类的bean,最后用getBean从容器中拿到这个bean。
<bean id="bookDao" name="dao bookDaoImpl" class="com.springquickstart.dao.impl.BookDaoImpl"></bean>
对于有依赖的两个类,博主新增了BookService接口和它的实现类,在它的实现类中,我们调用了前面BookDao的方法,所以我们BookService的实现类是依赖与我们的BookDao的。那如何表示两者的依赖关系呢?我们需要将两个实现类都丢到IoC容器中,也就是在xml中先写好这两个类的bean,然后使用property标签去配置两者都依赖关系。
<bean id="bookDao" name="dao bookDaoImpl" class="com.springquickstart.dao.impl.BookDaoImpl" ></bean>
<bean id="bookService" name="Service bookService2" class="com.springquickstart.service.impl.BookServiceImpl" >
<!--DI配置依赖关系-->
<!--name里面的bookDao指的是bookserviceimpl里面的那个bookDao(依赖对象)名字,ref里的则是bean标签中的-->
<property name="bookDao" ref="bookDao"></property>
</bean>
前面说的这种依赖是引用类型的依赖(什么是引用类型就默认大家懂了哈),当然还有简单(基本)类型,基本类型的注入方法其实就是property标签中ref属性换成value属性。就像下面这样👇
Bean
1.Bean的命名与别名
id 属性指定的最多一个名称
name属性中任意数量的其他名称的组合。
这种情况在大型系统中很常见,其中配置在每个子系统之间被分割,每个子系统都有自己的一组对象定义。 在基于xml的配置元数据中,可以使用元素来实现这一点。
alias
<alias name="fromName" alias="toName"/>
子系统A的配置元数据可以以【subsystemA-dataSource】的名称引用数据源。 子系统B的配置元数据可以以【subsystemB-dataSource 】的名称引用数据源。 当编写使用这两个子系统的主应用程序时,主应用程序以【myApp-dataSource】的名称引用数据源。 要使这三个名称都指向同一个对象,您可以向配置元数据添加以下别名定义:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
现在,每个组件和主应用程序都可以通过唯一的名称来引用dataSource,并且保证不会与任何其他定义(有效地创建了一个名称空间)发生冲突,但它们引用的是相同的bean。
2. 实例化bean
2.1 构造函数实例化
就是最普通的方法实例化bean:写一个类,然后xml配置写bean标签。但这种可能需要一个无参构造,如下
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
2.2 静态工厂实例化
先上一个静态工厂的实例。
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
注意: createInstance() 方法必须是一个静态方法
2.3 实例工厂实例化
实例工厂和静态工厂实例化的区别是一个有静态方法,一个没有。使用实例工厂需要有一个实例的bean。factory-bean写上这个实例的bean。如下
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
<bean id="accountService" factory-bean="serviceLocator" factory-method="createAccountServiceInstance"/>
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
3. Bean的作用范围
| scope | 描述 |
|---|---|
| singleto | 每个bean在ioc容器中都是独一无二的单例形式。 |
| prototype | 将单个beanDifination定义为,spring容器可以【实例化任意数量】的对象实例。 |
| request | 将单个beanDifination限定为单个HTTP请求的生命周期。 也就是说,每个HTTP请求都有自己的bean实例,它是在单个beanDifination的后面创建的。 仅在web环境中的Spring【ApplicationContext】的上下文中有效。 |
| session | 将单个beanDifination定义为HTTP 【Session】的生命周期。 仅在web环境中的Spring 【ApplicationContext】的上下文中有效。 |
| application | 将单个beanDifination定义为【ServletContext】的生命周期。 仅在web环境中的Spring 【ApplicationContext】的上下文中有效。 |
| websocket | 将单个beanDifination作用域定义为【WebSocket】的生命周期。 仅在web环境中的Spring【ApplicationContext】的上下文中有效。 |
4. 生命周期
方式一:
< bean id =" exampleInitBean " class =" examples.ExampleBean " init-method =" init "/>
< bean id =" exampleInitBean " class =" examples.ExampleBean " destroy-method =" cleanup "/>
方式2:注解
@PostConstruct
@PreDestroy
为同一个bean配置的多个生命周期机制(具有不同的初始化方法),调用顺序如下:
- 用“@PostConstruct”注解的方法
- afterPropertiesSet() 由 InitializingBean 回调接口
- 自定义配置的init()方法
Destroy方法的调用顺序相同:
- 用 @PreDestroy注解的方法
- destroy()由 DisposableBean 回调接口定义
- 自定义配置的 destroy() 方法
依赖注入
1. 构造函数的依赖注入
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo,ThingThree thingThree) {
// ...
}
}
1.1 根据参数顺序注入
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<!-- 直接写就可以 -->
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
1.2 根据参数类型注入
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
1.3 按下标注入
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
1.4 构造函数参数名字匹配
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
2. 基于setter的注入
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="misterkaoli"/>
</bean>
2.1 注入数组类型数据
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
2.2 注入List类型数据
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
2.3 注入Set类型数据
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
2.4 注入Map类型数据
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
2.5 注入Properties类型数据
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写、、、、标签
3. 自动装配
配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
基于注解的自动装配@Autowired
@Qualifier微调基于注解的自动装配
@Value注入简单类型
@Component("bookService")
public class BookServiceImpl implements BookService {
//依赖bookdao
@Autowired
@Qualifier("bookDao")
private BookDao bookDao;
//注入简单类型
//@Value("bookdao1")
@Value("${name}")
private String name;
@Override
public void save() {
System.out.println("book service save..."+name);
bookDao.save();
}
}
@Resource 带有一个name属性。 默认情况下,Spring将该值解释为要注入的bean名。 换句话说,它遵循by-name语义,如下面的示例所示:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
注解开发常用注解
@Component代替bean注册
@Repository 、@Service 和 @Controller是【@Component】用于更具体用例的注解(分别在持久性、服务和表示层中)。
@Configuration声明配置类,相当于刚生成spring的xml配置最上边那部分。
@ComponentScan写到配置类上方,就是自动扫描指定包中的注解。
@Autowired基于注解的自动装配
@Qualifier微调基于注解的自动装配
@Value注入简单类型
@Scope("prototype") 与xml中bean的scope作用一样
@Bean表示当前方法的返回值是一个bean对象,添加到IOC容器中。
@Import注解导入式
@PropertySource加载properties配置文件@PropertySource({"classpath:jdbc.properties"})
@Bean注解用于指示一个方法,该方法负责【实例化、配置和初始化】一个由Spring IoC容器管理的新对象。 对于那些熟悉Spring XML配置的人来说,@Bean注解扮演着与 元素相同的角色。 你可以在任何Spring @Component中使用@Bean注解方法。 但是,它们最常与@Configuration一起使用。
举例:
public class JdbcConfig {
//@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
@Configuration
@ComponentScan("com.itheima")
//@Import:导入配置信息
@Import({JdbcConfig.class})
public class SpringConfig {
}
今天就先更新到这里,明天续更。。。。。。