一、Spring 简介
1、什么是 Spring
Spring 是一个用于简化企业级 Java 开发的利用框架
Spring 以 IoC(管制反转)和 AOP(面向切面编程)为外围,提供了体现层的 SpringMVC 反对,也提供了业务层的申明式事务反对,以及提供了长久层的 JdbcTemplate 反对。Spring 除了本身所提供的性能外,还能够作为一个粘合剂,用于整合优良的第三方技术框架。SSH(spring 整合 Struts2、spring 整合 Hibernate)SSH(spring 整合 SpringMVC、spring 整合 Mybatis)
2、Spring 的劣势
1)不便解耦,简化开发
2)提供了 AOP、申明式事务反对(前面阶段解说)3)对 JavaEE 进行了封装,升高开发难度。。。
二、Spring 的 IoC
1、耦合、解耦的概念
耦合: 是指对象和对象之间产生的依赖关系, 依赖关系越高, 耦合性越高, 依赖关系越低, 耦合性越低。在开发我的项目时,尽量不要让对象之间的依赖关系太高。解耦: 升高对象之间耦合性的过程叫做解耦(解耦只是升高耦合性, 但不能彻底消除)
Class AnimalTest{Animal ani = spring 容器对象.getBean("animal")
//Animal ani = new Cat();}
interface Animal{}
class Cat implements Animal{}
------------------------------------------------
beans.xml
animal com.tedu.Cat
2、Spring IoC 概念
IoC(Inverse Of Control):管制反转,是指将对象的创立交给框架负责
在 spring 框架之前,当须要对象,咱们负责管制对象的创立(new 的模式),以及对象的销毁
但因为 new 对象会造成对象之间的依赖关系晋升(即耦合度晋升)
因而能够将对象的创立交给 spring 负责,将创建对象的权力交给框架,这里咱们称之为 "管制反转"
3、Spring IoC 入门
1)创立 Maven 的 java 工程:CGB-SPRING-01
2)在 pom.xml 文件中导入 junit、spring 的依赖包
3)提供 com.tedu.pojo.User 类(将 User 类的实例交给 spring 框架创立)
4)在 src/main/resources 下提供 spring 的配置文件 --beans.xml, 并增加如下配置
<!-- 将 User 作为 bean 拆卸到 spring 容器中(将 User 类的实例交给 spring 容器创立)
id 属性: 定义一个编号, 未来通过这个编号能够获取以后类的实例(id 必须是惟一的)id 值通常是以后类的类名(但首字母小写), 或者以后类父接口的接口名(首字母小写)
class 属性: 指定以后类的全类名(spring 框架会通过反射 + 全类名创立该类的实例) -->
<bean id="user" class="com.tedu.pojo.User">
5)提供测试类,测试 spring 的 IoC
public class SpringTest {
// 获取 spring 的容器对象
ClassPathXmlApplicationContext ac =
new ClassPathXmlApplicationContext("beans.xml");
/* 1、测试 spring 的 IoC */
@Test
public void testIoC(){// 从 spring 容器中获取 User 类的实例(对象)
User user = (User)ac.getBean("user"); // 依据 id 获取 bean
}
}
三、Spring 的单实例和多实例
/*
* 单例: 默认 spring 容器中所有的 bean 对象都是单例的(即每个类只创立一个对象)
* 长处: 无论获取一个 bean 多少次, 返回都是同一个实例(因为只创立了一个实例)
* 能够节俭内存空间, 缩小资源节约。* 毛病: 可能会引发线程平安问题(如果这个惟一对象上有共享数据, 并且多个线程会同时
* 操作这个共享数据)* 单例的 bean 是在 beans.xml 文件一被读取就会创立实例, 而且会存到 bean 池中
*
* 多例: 如果在 bean 标签上设置 scope="prototype", 以后 bean 对象就是多例的
* <bean id="user" scope="prototype" class="com.tedu.pojo.User">
* 每次获取以后类的实例, spring 容器都会创立该类的新的实例
* 长处: 不会引发线程平安问题(因为每个线程持有的实例是不同的)
* 毛病: 因为每次获取都会创立新的实例, 会占用服务器的内存空间, 浪费资源
* 多例的 bean 是每次获取时才会创立实例, 而且创立的实例不会存到 bean 池中
*
* 总结: 从应用频次上, 如果一个对象应用的频率特地高, 倡议应用单例
* 反过来说, 如果一个对象应用频率特地低, 倡议应用多例。*/
@Test
public void testScope() {// 获取 UserInfo 类的实例(多例)
UserInfo info1 = (UserInfo)ac.getBean("userInfo");
UserInfo info2 = (UserInfo)ac.getBean("userInfo");
System.out.println(info1 == info2); //false, 地址不相等, 阐明不是同一个对象
// 获取 User 类的实例(单例)
User u1 = (User)ac.getBean("user");
User u2 = (User)ac.getBean("user");
System.out.println(u1 == u2); //true, 因为是同一个对象, 所以地址相等
}
四、Spring 的 DI
/*
* 测试 spring 的 DI(依赖注入)* 依赖注入:在创建对象的同时或者之后,为对象的属性赋值
* 1)set 办法注入:在创建对象之后,框架在底层调用对象的 setXxx 办法为 xxx 属性赋值
* 例如: 调用 setName 办法给 name 属性赋值
* 2)构造方法注入:底层是在创建对象的同时, 通过构造方法给对象的属性赋值
*/
@Test
public void testDI() {
// 获取 User 类的实例
User user = (User)ac.getBean("user");
System.out.println(user);
}
========================================================
<!-- 应用 set 办法为 User 对象的 name、age、info 变量赋值
须要留神的是: name 属性指定的值, 在以后类中得有对应的 set 办法 -->
<bean id="user" class="com.tedu.pojo.User">
<property name="name" value="韩少云" />
<property name="age" value="30" />
<property name="info" ref="userInfo"/>
</bean>
========================================================
<!-- 应用构造方法为 User 对象的 name、age、info 属性赋值
其中 name 属性的值 要和构造方法上形参的名字保持一致
-->
<bean id="user" class="com.tedu.pojo.User">
<constructor-arg name="name" value="马云"/>
<constructor-arg name="age" value="38"/>
<constructor-arg name="info" ref="userInfo"/>
</bean>
========================================================
五、Spring 的全注解开发
1、spring 全注解开发入门
1)创立 Maven 的 java 工程:CGB-SPRING-02
2)在 pom.xml 文件中导入 junit、spring 的依赖包
3)提供 com.tedu.pojo.User 类(将 User 类的实例交给 spring 框架创立)
4)提供 com.tedu.AppConfig 类,作为 Java 配置类
========================================================
/* @Configuration: 告诉 spring 框架这是一个 Java 配置类, spring 框架通过
* 这个类中的配置, 生成 spring 容器对象。AppConfig 类 == beans.xml 文件
*/
@Configuration
public class AppConfig {/* @Bean(name="user"): 将以后办法的返回值作为 bean 拆卸到 spring 容器中
* 其中 name 指定的值就是 bean 的 id 值(即 bean 的名称), 相当于 <bean> 标签
* 如果不增加括号及其中的 name 属性, bean 的 id 值就是办法名 */
@Bean(name="user")
public User getUser() {User user = new User();
user.setName("赵云");
user.setAge(28);
return user;
}
}
========================================================
5)提供测试类,测试 spring 的全注解开发
public class SpringTest {
// 获取 spring 的容器对象
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(AppConfig.class);
/* 1、测试 spring 的全注解开发 */
@Test
public void testIoC01() {
// 从 spring 容器中获取 User 类的实例
User u1 = (User)ac.getBean("user");
System.out.println(u1);
}
}
2、通过扫描拆卸 Bean
1)将下面 AppConfig 中 @Bean 注解及标记的 getUser 办法 正文或者间接删除
2)在 AppConfig 类上增加 @ComponentScan 注解
/* @Configuration: 告诉 spring 框架这是一个 Java 配置类, spring 框架通过
* 这个类中的配置, 生成 spring 容器对象。AppConfig 类 == beans.xml 文件
* @ComponentScan: 用于配置以何种策略扫描拆卸 bean, 如果前面什么都不加
* 默认扫描以后类所在的包 (com.tedu) 及其子包(com.tedu.*)
* 如果扫描到包中的类上有 @Component 注解, 就会将这个类作为 bean 进行拆卸
*/
@Configuration
@ComponentScan
public class AppConfig {/* ... */}
3)在 User 类上增加 @Component("user") 注解
@Component("user")
public class User {...}
4)再执行 SpringTest 类中 testIoC01 办法进行测试
@ComponentScan: 配置以何种形式扫描拆卸 bean, 默认扫描以后类所在的包及其子包
比方, 以后类是 com.tedu.AppConfig, 所在的包就是 com.tedu
默认扫描的包就是 com.tedu 包以及以 com.tedu 结尾的所有子包
@ComponentScan(basePackages = "com.tedu.dao")
basePackages 指定扫描哪个包, 下面指定了只扫描 com.tedu.dao 包
@ComponentScan(basePackages = { "com.tedu.dao", "com.tedu.service"} )
basePackages 同时能够指定扫描多个包, 将多个包放在一个数组中即可,
下面指定了扫描 com.tedu.dao 包 和扫描 com.tedu.service 包
3、@AutoWired 主动拆卸(依赖注入)
如果是给一个字符串类型的变量或者数值类型的变量赋值, 能够间接通过 @Value 注解给对象的属性赋值。1)批改 User 类, 在 User 类中增加一个 Animal 类型的 animal 属性, 并提供对应的 get 和 set 办法
2)重写 User 类中的 toString 办法
3)增加一个 com.tedu.pojo.Animal 接口, 并未 Animal 接口提供一个实现类 --com.tedu.pojo.Dog
4)通过 @AutoWired 注解为 User 对象的 animal 属性赋值, 赋的值是一个 Animal 类型的对象
@Component("dog") // 将 Dog 类作为 bean 拆卸到 spring 容器中(spring 容器中是蕴含 Dog 对象的)public class Dog implements Animal
@Autowired
private Animal animal;
@Autowired 注解的作用:1)@AutoWired 注解是咱们应用十分多的注解之一,它能够将定义好的 bean 对象(比方 Dog 对象)作为值 赋值给其它对象的属性。这个过程是主动实现的,咱们称之为主动拆卸(依赖注入)2)@AutoWired 注解默认优先依照(Animal)类型到 spring 容器中进行查找 bean,如果找到一个则间接将这个 bean 对象作为值赋值给 animal 属性。如果找不到,则抛出异样!3)如果该类型(Animal)的 bean 在 spring 容器中有多个,此时还会依据变量名 / 属性名去匹配,如果变量名 / 属性名 和 bean 的 id 值雷同,就能够主动拆卸。如果都不雷同,也会抛出异样。4)如果该类型(Animal)的 bean 在 spring 容器中有多个,能够通过 @Qualifier 显式的为属性指定要注入哪一个名称的 bean
4、@Scope 指定 bean 的作用范畴
@Scope("prototype")
public class User{...}
如果不指定 scope 属性或者 @Scope 注解, 在 spring 容器中所有的 bean 都是单实例的(spring 容器为所有的类只创立一个实例。)
如果指定 scope="prototype" 或者 @Scope("prototype"), 能够指定以后 bean 为多实例, 即每次通过 spring 容器获取以后类的实例, 都会创立新的 bean 对象并返回!