Spring简介
Spring是一个开源的控制反转(Inversion of Control ,IoC)和面向切面(Aspect Oriented Programmin ,AOP)的容器框架.
IOC和AOP是它的两个重要特性。
依赖注入(Dependency Injection,DI)是控制反转的重要部分,它的主要目的是简化企业开发。
Spring简化了企业应用程序开发复杂性,弱化了系统组件间的藕合度,它由Rod Johnson创建的。
什么是控制反转(IOC)
所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。
什么是依赖注入(Di)
所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中。
举例说明 Ioc 和 Di
Dao层
public interface StudentDao {
public int delete();
}
两个实现类:
StudentDaoImplMySql
public class StudentDaoImplMySql implements StudentDao {
@Override
public int delete() {
System.out.println("使用mysql删除数据");
return 0;
}
}
StudentDaoImplOracle
public class StudentDaoImplOracle implements StudentDao {
@Override
public int delete() {
System.out.println("使用oracle删除数据");
return 0;
}
}
服务层
public class StudentService {
StudentDao studentDao;
public StudentService(StudentDao studentDao) {
this.studentDao = studentDao;
}
public void delete() {
studentDao.delete();
}
}
使用
public class Test {
public static void main(String[] args) {
//由客户端决定使用那个数据库
StudentService studentService = new StudentService(new StudentDaoImplMySql());
studentService.delete();
}
}
由外部创建要使用的对象,这叫控制反转(本来应该由服务层创建)例如在Spring容器创建对象
客户端将创建的对象传入服务层,这是依赖注入
使用Spring优势
在项目中引入spring立即可以带来下面的好处
降低组件之间的耦合度,实现软件各层之间的解耦。
可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务,也不需处理复杂的事务传播。
容器提供单例模式支持,开发人员不再需要自己编写实现代码。
容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate。
Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts2等,这样更便于应用的开发。
使用Spring需要的jar
使用maven仓库。
使用Idea添加Spring应用
确定项目与maven仓库关联。
创建maven项目
<groupId>com.entor</groupId>
<artifactId>spring_maven</artifactId>
<version>1.0-SNAPSHOT</version>
在pom.xml文件中的dependencies标签中添加依赖具体到mvnrepository网址查找
<dependencies>
<!--所有依赖写在这儿-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
</dependencies>
下载的依赖在:D:\maven\repository\org.springframework\spring-webmvc\5.3.5 中
maven会自动将该依赖的需要的其他jar包一起导入。
当下载失败时,应该将刚刚下载的jar包和依赖删除并且重新刷新maven让其重新下载。
依赖注入(DI)
使用构造器注入
使用属性setter方法注入
使用Field注入(用于注解方式)
注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。
1.手工装配依赖对象
2.自动装配依赖对象
Spring配置文件(手工装配)
在resource目录下创建applicationContext.xml
配置文件的属性和赋值(set方法注入和构造方法注入)
applicationContext.xml文件就是spring容器,把需要该容器创建的对象的类通过bean标签配置在此即可
默认加载该文件时创建对象,每一个bean标签只创建一个对象,单例模式。
id="student",获取对象名称,唯一。
class="com.eator.entity.Student",类的全限定名,根据反射创建对象。
lazy-init="true"延迟创建对象,在使用该对象时才创建并初始化,缩短spring容器的启动时间,节省内存空间。
scope="prototype",每次调用创建创建一个新的对象。默认为singleton只创建一个。
init-method="init对象创建时调用该方法,只执行一次
destroy-method="destroy对象销毁时调用该方法,只执行一次
set注入和构造方法注入必须在实体类写上对应的set方法和构造方法
set 方法赋值
applicationContext_bean.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">
<!--一个bean标签创建一个对象 id值唯一-->
<!--基本类型赋值-->
<bean id="student"
class="com.eator.entity.Student"
lazy-init="true"
scope="prototype"
init-method="init"
destroy-method="destroy">
<!--
赋值,自动调用set方法
开闭标签内不写东西可以写成单标签
-->
<property name="id" value="1"/>
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
<bean id="bean" class="com.eator.entity.Bean">
<property name="intVal" value="1"/>
<property name="strVal" value="张三"/>
<!--数组类型赋值-->
<property name="arrays">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
<!--list集合赋值-->
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
<!--set集合赋值-->
<property name="set">
<set>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</set>
</property>
<!--Map类型对赋值-->
<property name="map">
<map>
<entry key="CN" value="中国"/>
<entry key="EN" value="美国"/>
<entry key="JP" value="日本"/>
</map>
</property>
<!--Properties类型对赋值-->
<property name="properties">
<props>
<prop key="CN">中国</prop>
<prop key="EN">美国</prop>
<prop key="JP">日本</prop>
</props>
</property>
</bean>
</beans>
构造方法和引用(ref、实体类赋值)赋值
<?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">
<!--导入其他配置文件,按照导入顺序加载,bean的创建顺序默认根据配置的先后顺序创建对象-->
<import resource="applicationContext.xml"></import>
<bean id="bean1" class="com.eator.entity.Bean1">
<!--
set 方法
<property name="bean2" ref="bean2"/>
<property name="bean3" ref="bean3"/>
-->
<!--构造方法 index第几个参数 ref 引用bean的id -->
<constructor-arg index="0" ref="bean2"/>
<constructor-arg index="1" ref="bean3"/>
</bean>
<bean id="bean2" class="com.eator.entity.Bean2"></bean>
<bean id="bean3" class="com.eator.entity.Bean3" ></bean>
</beans>
属性注解注解Autowired、Qualifier和Resource的使用
开启注解:修改头部参数,和添加标签<context:annotation-config/>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解模式 只有开启注解模式注解才能获取配置文件内的对象-->
<context:annotation-config/>
<!--导入其他配置文件,按照导入顺序加载,bean的创建顺序默认根据配置的先后顺序创建对象-->
<import resource="applicationContext.xml"></import>
<bean id="bean1" class="com.eator.entity.Bean1">
</bean>
<bean id="bean2" class="com.eator.entity.Bean2"></bean>
<bean id="bean3" class="com.eator.entity.Bean3"></bean>
</beans>
实体类:
/**
* @Resource 作用在属性上,默认根据属性名称去配置文件中查找对应的id来创建对象,然后赋值给变量(直接赋值不用set方法和构造方法)
* 如果找不到对应的id,则根据属性类型去查找,如果没有对应的属性类型或着有多个则报错。
* 注解可以指定name 属性根据指定的名称去配置文件查找对应的id,一旦指定了名称只会根据名称查找则报错。
* @Autowired 作用在属性上,根据默认的类型去配置文件查找对应的bean,创建对象后赋值给该属性变量。
* 如果找不到或找到多个,则根据属性名称去查找bean,如果找不到则报错。
* 可以配合@Qualifier注解设置value值来查找id,查不到就报错。
* 总结:直接作用在属性上,set和get方法可以省略。
*/
public class Bean1 {
// @Resource(name = "bean2")
@Autowired
@Qualifier(value = "bean2")
private Bean2 bean2;
@Resource
private Bean3 bean3;
}
类注解Controller、Service、Repository、Component和Scope
* 以下四个注解作用在类上功能相同,根据规范写在不同的地方。作用:相当于在配置文件中配置bean,id默认是根据类的首字母小写value指定id,默认单例模式。
* @Controller 用在控制层
* @Service 用在业务层
* @Repository 用在数据访问层
* @Component 除了上面三个之外的不好区分的类用这个注解
*
* @Scope(value = "prototype") 使得创建对象时创建多个
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--主键包扫描,指定包以及自包路径下的所有被@Compnent @Controller @Service @Repository标注过的类,都创建对象-->
<context:component-scan base-package="com.eator.entity"/>
</beans>
从配置文件中获取对象
public class Test {
public static void main(String[] args) {
/* //自己创建对象
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
System.out.println(student);*/
//把对象创建工作交给Spring容器集中创建,要用的时候直接去Spring容器中去取。
//1、加载spring配置文件,启动spring的容器,创建对象。每一分bean标签只创建一个对象,单例模式。默认加载文件时创建。
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2、从spring从容器中获取对象
Student student = (Student)context.getBean("student");//根据id取对象
Student s = context.getBean(Student.class);//根据类型取对象,有风险(多个则报错)。
//3、使用对象
System.out.println(student);
System.out.println(student==s);
多个配置文件时获取对象
导入配置文件
创建新的xml文件(applicationContext_bean.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">
<!--导入其他配置文件,按照导入顺序加载,bean的创建顺序默认根据配置的先后顺序创建对象-->
<import resource="applicationContext.xml"></import>
<bean id="bean1" class="com.eator.entity.Bean1"></bean>
<bean id="bean2" class="com.eator.entity.Bean2"></bean>
<bean id="bean3" class="com.eator.entity.Bean3" ></bean>
</beans>
获取对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_bean.xml");
Bean bean = context.getBean(Bean.class);
Bean1 bean1 = context.getBean(Bean1.class);
Bean2 bean2 = context.getBean(Bean2.class);
Bean3 bean3 = context.getBean(Bean3.class);
通过占位符的方式
applicationContext*.xml 代表所有以applicationContext开头的xml文件(注意id唯一)
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext*.xml");
Bean bean = context.getBean(Bean.class);
Bean1 bean1 = context.getBean(Bean1.class);
Bean2 bean2 = context.getBean(Bean2.class);
Bean3 bean3 = context.getBean(Bean3.class);
使用注解Configuration替代配置文件
@Configuration 作用在类上,相当于该类是一个applicationContext.xml配置文件文件
与@Controller @Repository @Service @Component功能相同,多了一个容器的职能。
@Configuration
public class SpringConfig {
/**
* @Bean 此注解多用在方法中,相当于在配置中配置了一个bean标签,IOC会自动创建该对象
*/
@Bean(initMethod = "init")//创建对象时的初始化方法。
@Lazy//延迟加载,使用时才创建。默认是加载IOC容器就创该对象
@Scope(value = "prototype")//每次调用创建新的对象,默认单例、
public Bean1 bean1() {//id值为方法名,该类中的方法不能重载。
return new Bean1();
}
@Bean
public Bean2 bean2() {
// Bean2 bean2 = new Bean2(bean3());//使用的对象是ioc创建好的对象,默认单例
Bean2 bean2 = new Bean2(new Bean3());//使用的对象是新的对象
return bean2;
}
@Bean
public Bean2 bean22(Bean3 bean3) {//IOC容器认为参数为其他方法,首先根据参数名称找方法,找不到根据类型找,找到多个则报错。
return new Bean2(bean3);
}
@Bean
public Bean3 bean3() {
return new Bean3();
}
}
获取对象
加载配置类,创建类中的各个对象
public class Test2 {
public static void main(String[] args) {
//加载配置类,创建类中定义的各个对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Bean1 bean1 = (Bean1) context.getBean("bean1");//根据方法名获取对象
}
}
(与上边的区别:获取包下的所有对象)
加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象放入IOC容器中
public class Test2 {
public static void main(String[] args) {
//加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com");
Bean2 bean2 = (Bean2) context.getBean("bean2");
Bean3 bean3 = (Bean3) context.getBean("bean3");
System.out.println(bean2);
System.out.println(bean3);
}
}
@Import注解的使用
@Import四种使用方法
第一种:直接导入类
自定义类
public class Bean6 {
}
导入
@Configuration
@Import({Bean6.class})
public class SpringConfig {
}
获取对象:只能通过类型和全限定名获取该对象
public class Test2 {
public static void main(String[] args) {
//加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com");
//通过指定类型获取对象,多个则报错
Bean6 bean6 = context.getBean(Bean6.class);
//通过全限定名来获取对象
//Bean6 bean6 = (Bean6)context.getBean("com.entity.Bean6");
System.out.println(bean6);
}
}
第二种:导入其他配置类(类中有@Bean注解),相当于配置文件中导入其他配置文件
配置类
public class BeanConfig {
@Bean
public Bean7 bean7() {
return new Bean7();
}
}
导入
@Configuration
@Import({BeanConfig.class})
public class SpringConfig {
}
获取对象:可以根据方法名获取和根据类型获取对象,导入的方法与原有的方法相同(同类型同名称)则为一个方法。
public class Test2 {
public static void main(String[] args) {
//加载配置类,创建类中定义的各个对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象
Bean7 bean2 = (Bean7)context.getBean("bean7");
System.out.println(bean2);
}
}
第三种:实现ImportSelector接口,可以动态添加类到ioc容器中进行创建对象
实现类
public class ImportBean implements ImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{Bean4.class.getName(), Bean5.class.getName()};
}
}
导入该实现类
@Configuration
@Import({ImportBean.class})
public class SpringConfig {
}
获取对象:只能通过全限定名和类型获取
public class Test2 {
public static void main(String[] args) {
//加载配置类,创建类中定义的各个对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Bean4 bean4 = (Bean4)context.getBean("com.entity.Bean4");
Bean5 bean5 = context.getBean(Bean5.class);
System.out.println(bean4);
System.out.println(bean5);
}
}
第四种:实现ImportBeanDefinitionRegistrar接口
实现类:可以指定名称
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("bean1", BeanDefinitionBuilder.rootBeanDefinition(Bean1.class).getBeanDefinition());
registry.registerBeanDefinition("bean2", BeanDefinitionBuilder.rootBeanDefinition(Bean2.class).getBeanDefinition());
}
}
导入
@Configuration
@Import({MyImportBeanDefinitionRegistrar.class})
public class SpringConfig {
}
获取对象:通过名称查询和类型查询
public class Test2 {
public static void main(String[] args) {
//加载配置类,创建类中定义的各个对象
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Bean1 bean1 = (Bean1)context.getBean("bean1");
Bean2 bean2 = context.getBean(Bean2.class);
System.out.println(bean1);
System.out.println(bean2);
}
}
总结
Spring是一个容器,负责创建对象(IOC)、和传对象(DI),减少了模块的耦合度,降低了程序的复杂度。