本文已参与「新人创作礼」活动,一起开启掘金创作之路。
目录
一.基于配置文件的IOC
1.利用Spring容器中获取对象
Step1:创建maven工程,在pom文件中添加Spring的核心jar包
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/com.springsource.org.apache.commons.logging --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>com.springsource.org.apache.commons.logging</artifactId> <version>1.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-provider-api</artifactId> <version>1.0</version> </dependency> </dependencies>
Step2:创建Spring核心配置文件
编辑
Step3:从Spring容器中获取对象
- 创建实体类
- xml文件中定义bean标签
- 创建ApplicationContext容器,并取出对象
<bean id="stu" class="pojo.Student"></bean> <!-- 等同于Student student = new Student(); id是创建的对象的名称,唯一标识这个bean class是创建对象的类型 启动容器的同时,这个对象就被创建了 -->
public static void getStudent(){ //2.从Spring容器中取出对象,得先创建容器对象,并启动才能取对象 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Student stu = (Student) ac.getBean("stu"); }
2.利用配置文件注入-通过Spring给对象赋值
使用setter注入
要求
使用setter注入时,实体类中必须有无参构造和set方法。
因为使用setter注入时,要先创建出对象,再给对象赋值,所以要有无参构造。
简单类型注入
通过property,name,value
public class Student { private String name; private int age; public Student() { System.out.println("学生无参构造"); } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } }
<bean id="stu" class="pojo.Student"> <property name="name" value="张三"></property> <property name="age" value="18"></property> </bean>
引用类型注入
通过property name ref
public class Student { private String name; private int age; private School school; public Student() { System.out.println("学生无参构造"); } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setSchool(School school) { this.school = school; } }
<bean id="school" class="pojo.School"> <property name="name" value="青岛大学"></property> <property name="address" value="青岛"></property> </bean> <bean id="stu" class="pojo.Student"> <property name="name" value="张三"></property> <property name="age" value="18"></property> <property name="school" ref="school"></property> </bean>
引用类型的自动注入
<bean name="student" class="pojo.Student" autowire="byType"> <property name="name" value="张三"></property> <property name="age" value="18"></property> <!-- <property name="school" ref=""></property>--> </bean> <bean name="school" class="pojo.School"> <property name="name" value="青大"></property> <property name="address" value="青岛"></property> </bean>
通过autowire自动注入引用类型,不需要写property标签了
使用构造方法注入
通过构造方法注入时,是在创建对象的过程中就赋值了,所以要有对应参数个数的构造方法,不能仅有无参构造。
使用构造方法的参数名称进行注入值
构造方法标签中的name属性值是构造方法形参的名字
public class School { private String name; private String address; public School(String name1, String address1) { this.name = name1; this.address = address1; } }
<bean id="school" class="pojo.School"> <constructor-arg name="name1" value="青岛大学"></constructor-arg> <constructor-arg name="address1" value="青岛"></constructor-arg> </bean>
使用构造方法参数的下标注入值
<bean id="school" class="pojo.School"> <constructor-arg index="0" value="青岛大学"></constructor-arg> <constructor-arg index="1" value="青岛"></constructor-arg> </bean>
构造器中的参数的顺序序号
使用默认的构造方法的参数的顺序注入值
<bean id="school" class="pojo.School"> <constructor-arg value="青岛大学"></constructor-arg> <constructor-arg value="青岛"></constructor-arg> </bean>
这个顺序是和构造器中参数的顺序一致
二.基于注解的IOC
要求
1.基于注解的IOC需要在Spring配置文件中添加包扫描,并且需要无参构造。
<context:component-scan base-package="pojo"></context:component-scan>
扫描包的方式
编辑
扫描根包会导致容器扫描很多无用的路径,使启动速度降低。
2.每个类要加上@Component注解
1.利用注解获取对象
编辑
扫描某个包,只要扫到包中哪个类有这几个注解,就马上创建这个类的对象。
@Component public class Student { private String name; private int age; private School school; }
public class Test { @org.junit.Test public void test(){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Student school = (Student) ac.getBean("student"); System.out.println(school); } }
用注解时获取对象时,默认对象的名字是类名的小写。如Student类的对象名是student
也可以给对象指定名字
@Component("stu") public class Student { private String name; private int age; private School school; }
2.利用注解注入
编辑
同源类型:
编辑
值类型注入
@Component("stu") public class Student { @Value("张三") private String name; @Value("18") private int age; }
引用类型按类型注入
扫描整个被Component注解的类,看哪个是School类型,School类型需要加上@Component注解才能被扫描到,被扫描到后就可以给引用类型赋值,因为类名不允许重,所以可以保证唯一。
@Component public class School { @Value("青岛大学") private String name; @Value("青岛") private String address; }
@Component public class Student { @Value("张三") private String name; @Value("18") private int age; @Autowired private School school; }
引用类型按名称注入
按名称注入时,只要@Qualifier不能承担起这个功能,必须还要有@Autowired这个注解
@Component("sch") public class School { @Value("青岛大学") private String name; @Value("青岛") private String address; }
@Component public class Student { @Value("张三") private String name; @Value("18") private int age; @Autowired @Qualifier("sch") private School school; }
有父子类的情况
使用按类型注入时,意味着有多个可注入的对象,假如要注入School类型,而SubSchool继承School,那么School类和SubSchool类都属于School类,注入时选择哪个类的对象呢?
这时会按照名称进行二次筛选,比如要注入School类型,就去筛选school名称的对象,School类的默认名称是school,SubSchool类的默认名称是subSchool,名称是可以通过@Component("")来修改的
按名称注入值时, 跟上面无父子类的情况一样。
三.Spring配置文件的拆分和整合
当项目越来越大,需要多人合作开发,一个配置就存在很大的隐患,所以需要拆分。
拆完编辑好之后就需要组合到一起才能实现功能。
编辑
按层拆分的例子
编辑
基于注解时每个applicationContext都是扫描包,不使用注解时,每个配置文件写的是bean。
单个导入
<?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"> <!-- 单个导入--> <import resource="applicationContext_controller.xml"></import> <import resource="applicationContext_service.xml"></import> <import resource="applicationContext_mapper.xml"></import> </beans>
批量导入
<?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"> <!-- 批量导入--> <import resource="applicationContext_*.xml"></import> </beans>
四.其他
三层架构
编辑
model层也叫pojo层或entity层
dao层也叫mapper层
service层
controller层
创建对象
单态模式
<bean id="user" class="pojo.User" scope="singleton"></bean>
原型模式
<bean id="user" class="pojo.User" scope="prototype"></bean>
单态模式中调用getBean如果id相同,返回的对象是同一个,原型模式中调用几次getBean就会产生几个对象
在代码中获取对象
public static void getUser(){
//加载spring.xml配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
User user = (User) ac.getBean("user2");
}
注入(给对象属性赋值)
1.简单数据类型
public class User {
private String username;
private int age;
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
">
<bean id="user" class="pojo.User" scope="singleton">
<property name="username" value="cc"></property>
<property name="age" value="18"></property>
</bean>
</beans>
2.引用数据类型注入
public class User {
private String username;
private int age;
private Account account;
}
<bean id="user" class="pojo.User" scope="singleton">
<property name="username" value="cc"></property>
<property name="age" value="18"></property>
<property name="account" ref="account"></property>
</bean>
<bean id="account" class="pojo.Account">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="money" value="100"></constructor-arg>
</bean>
3.构造器注入
public class User {
private String username;
private int age;
public User() {
}
public User(String username, int age) {
this.username = username;
this.age = age;
}
}
<bean id="user2" class="pojo.User">
<constructor-arg name="username" value="zz"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
局部和全自动注入
局部自动注入,只在某个bean中有效
<bean id="user" class="pojo.User" scope="singleton" autowire="byName">
<property name="username" value="cc"></property>
<property name="age" value="18"></property>
<!-- <property name="account" ref="account"></property>-->
<!-- user有个名为account的属性,如果没有给这个属性赋值,会自动去寻找在bean中名为account的属性自动注入-->
</bean>
<bean id="account" class="pojo.Account">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="money" value="100"></constructor-arg>
</bean>
<bean id="user" class="pojo.User" scope="singleton" autowire="byType">
<property name="username" value="cc"></property>
<property name="age" value="18"></property>
<!-- <property name="account" ref="account"></property>-->
<!-- 通过类型注入,名字不一样,但是都属于Account类,也可以根据这个来判断注入-->
</bean>
<bean id="acc" class="pojo.Account">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="money" value="100"></constructor-arg>
</bean>
全局自动注入
写到这上面的话,就可以全局自动注入,每个bean都默认根据类型注入
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byType">
</beans>
空字符串注入
方式1
<bean id="user" class="pojo.User" scope="singleton" autowire="byType">
<property name="username" value=""></property>
<property name="age" value="18"></property>
</bean>
方式2
<bean id="user" class="pojo.User" scope="singleton" autowire="byType">
<property name="username"><value/></property>
<property name="age" value="18"></property>
</bean>
null值注入
<bean id="user" class="pojo.User" scope="singleton" autowire="byType">
<property name="username"><null/></property>
<property name="age" value="18"></property>
</bean>
什么也不写也是注入null
<bean id="user" class="pojo.User" scope="singleton" autowire="byType">
<property name="age" value="18"></property>
</bean>
数组注入集合properties注入
<bean id="data" class="pojo.Data">
<property name="arr">
<array>
<value>A</value>
<value>B</value>
<value>C</value>
<value>D</value>
</array>
</property>
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="set">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="map">
<map>
<entry key="m" value="3"></entry>
<entry key="n" value="3"></entry>
<entry key="q" value="3"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="zxc">123</prop>
<prop key="asd">456</prop>
</props>
</property>
</bean>
public class Data {
private String[] arr;
private List list;
private Set set;
private Map<String,Integer> map;
private Properties properties;
public String[] getArr() {
return arr;
}
public void setArr(String[] arr) {
this.arr = arr;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public Map<String, Integer> getMap() {
return map;
}
public void setMap(Map<String, Integer> map) {
this.map = map;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
基于注解注入
编辑
public class Test {
public static void main(String[] args) {
Test.getUser();
}
public static void getUser(){
//加载spring.xml配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
User user = (User) ac.getBean("user");
System.out.println(user);
}
}
@Component //表示在扫描pojo这个包下所有的类时,告诉spring容器当前User这个类交给Spring容器管理
//默认将类名的小写作为id名
public class User {
@Value("zz")
private String username;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
@Value("18")
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"username='" + username + ''' +
", age=" + age+'}' ;
}
}
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--当前配置文件被加载时,扫描这个包下所有的实体类-->
<context:component-scan base-package="pojo"></context:component-scan>
</beans>
也可以更改默认id名
@Component("uu")
public class Test {
public static void main(String[] args) {
Test.getUser();
}
public static void getUser(){
//加载spring.xml配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
User user = (User) ac.getBean("uu");
System.out.println(user);
}
}
@Scope注解
@Component()
//@Scope("singleton")
@Scope("prototype")
public class User {
@Value("zz")
private String username;
private int age;
}
@Autowired注解
根据类型自动匹配
@Component()
public class User {
@Value("zz")
private String username;
private int age;
@Autowired
private Account account;
@Component
public class Account {
@Value("10")
private int id;
@Value("100")
private double money;
}
@Resouce注解
@Required表示必须赋值,如果不赋值就会报错
如果在set方法上加了Required声明,那么必须把@Value放在set方法上,不能放在属性上
\