1.1简介
- 春天,spring就是java的春天
- spring本身就是一个大杂烩,它的理念就是使现有的框架更容易使用,整合了现有的技术框架。说白了spring就是一个整合剂。
- 开源、免费、轻量级的非入侵式的框架
- IOC和AOP
- 对事务的支持,对框架整合的支持
1.2环境搭建
导包
直接导webmvc这个包,可以把其他很多需要的功能包一并导入,
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
具体的包:
传统写法的困境
如果传统写法,我们要获取mysql数据库的用户信息,则需要调接口:
package com.mao.service;
import com.mao.dao.UserDao;
import com.mao.dao.UserDaoMySqlImpl;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl();
public void getUser(String username) {
userDao.getUser(username);
}
}
然而当实际应用中调用该接口的用户想获取Oracle数据库的用户信息的时候,又不得不该源代码,把UserDaoMySqlImpl()改为UserDaoOracleImpl(),这样的代码显然是及其低效的,所以我们不应该让程序员去控制对象的生成(即对象生成的管理权交给程序员),而应该让客户去调用接口来生成指定的实现类,这就是所谓的控制反转。
IOC本质
控制反转是一种设计思想,而DI(依赖注入)是其一种具体的实现方式。我们在使用面向对象编程的时候,对象的创建及对象的依赖关系完全通过硬编码来实现,而控制翻转则是将依赖的关系管理交给了第三方容器去管理,所以获得依赖的方式反转了。
**控制反转是一种通过描述(XML或者注解)**并通过第三方去生产或获取特定对象的方式。在spring中实现控制反转的是IoC容器,其实现方法是依赖注入。
总结:spring中对象的创建和对象属性的赋值都是由spring容器来执行的。控制反转中的控制就是谁来控制对象的创建,而反转则是程序本身不创建对象,是由主动的编程变成了被动的接收。
注意:其中要注意必须在实体类中有set方法才能给属性注入值
IOC实战
实体类:
package com.mao.pojo;
import lombok.Data;
@Data
public class User {
private String name;
private String age;
private String hobbies;
public void sayHi(){
System.out.println("大家好,我的名字叫"+name+",我今年"+age+"岁了,我的爱好是:"+hobbies);
}
}
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="user" class="com.mao.pojo.User">
<property name="name" value="童胖"></property>
<property name="age" value="10"></property>
<property name="hobbies" value="唱,跳,rap"></property>
</bean>
</beans>
测试:
package com.mao;
import com.mao.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User user = (User)applicationContext.getBean("user");
user.sayHi();
}
}
输出:
IOC创建对象的方式
默认使用无参构造创建对象,想要用有参构造,就要在<bean></bean>
中使用construct-arg标签设置
spring配置
别名
<!-- id:bean的唯一标识名,class是指定的类名,name也是别名,还可以指定多个,用“,”分隔 -->
<bean id="user" class="com.mao.pojo.User" name="xvshaoqing,xvshenghui">
<property name="name" value="童胖"></property>
<property name="age" value="10"></property>
<property name="hobbies" value="唱,跳,rap"></property>
</bean>
<alias name="user" alias="tongpang"></alias>
import导入
ClassPathXmlApplicationContext(String…files)可以指定多个xml配置,然而我们开发中也可以在一个xml配置文件中引入多个配置文件,相当于多合一了,如:
<!-- 这是application.xml文件 -->
<import resource="beans.xml">
通过以上方式就把beans.xml引入到了applicaiton中了。
DI依赖注入
有三种实现方式:
一、构造器注入
通过构造器为属性赋值
二、Set方式注入(重点)
依赖注入:分成两部分来理解
依赖:依赖spring容器来创建
注入:bean对象中的所有属性,由容器来注入
环境搭建
复杂对象:
package com.mao.pojo;
import lombok.Data;
@Data
public class Address {
private String address;
}
真实测试对象:
package com.mao.pojo;
import lombok.Data;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@Data
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
beans.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="stu1" class="com.mao.pojo.Student">
<property name="name" value="童小卿"></property>
</bean>
</beans>
测试类:
package com.mao.test;
import com.mao.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DiTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student stu1 = (Student) context.getBean("stu1");
System.out.println(stu1.getName());
}
}
DI完整实战
beans.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="address" class="com.mao.pojo.Address">
<property name="address" value="坎墩大昌车业"></property>
</bean>
<bean id="stu1" class="com.mao.pojo.Student">
<property name="name" value="童小卿"></property>
<property name="address" ref="address"></property>
<property name="books">
<array>
<value>三国演义</value>
<value>红楼梦</value>
<value>水浒传</value>
<value>西游记</value>
</array>
</property>
<property name="games">
<set>
<value>LoL</value>
<value>王者荣耀</value>
<value>刺激战场</value>
</set>
</property>
<property name="card">
<map>
<entry key="身份证" value="33028219951115343X"></entry>
<entry key="银行卡" value="622384218312731357321"></entry>
</map>
</property>
<property name="hobbys">
<list>
<value>唱</value>
<value>跳</value>
<value>rap</value>
</list>
</property>
<property name="wife">
<null/>
</property>
<property name="info">
<props>
<prop key="身高">185cm</prop>
<prop key="体重">90KG</prop>
<prop key="发型">自然卷</prop>
</props>
</property>
</bean>
</beans>
输出结果:
Bean的作用域
Scope就是作用域,可以在<bean>
标签中去设置,其中singleton是单例模式,表示单例,spring默认是单例的。prototype是原型模式,就是拷贝一个新对象,具体可以看我写的设计模式。另外request,session,application等只能在web应用中使用。
spring的自动装配
- 自动装配是spring满足bean依赖的一种方式。
- Spring会在上下文中自动寻找,并自动给bean装配属性
在spring中有3中装配方式:
- 在xml中显示地配置
- 在java中显示配置
- 隐式的自动装配【重要】
<?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="cat" class="com.mao.pojo.Cat"></bean>
<bean id="dog" class="com.mao.pojo.Dog"></bean>
<bean id="person" class="com.mao.pojo.Person" autowire="byName">
</bean>
</beans>
ByName
上述代码中autowire="byName"就是自动在容器上下文中去寻找和自己set方法后面的值相对应的beanid对应的对象。因此当我们使用id为cat和dog的时候我们可以成功注入,但是当把dog改成dog111的时候就报空指针了:
ByType
会在容器上下文中寻找和想要注入属性同一类型的数据,但是必须保证只有一个该类的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"
xmlns:context="http://www.springframework.org/schema/context"
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">
就是xmlns:context这段以及在约束中添加的内容。
2. 配置注解的支持(beans.xml)
<context:annotation-config/>
该注解非常重要,如果不用的话就无法使用注解。
@Autowired
直接在属性上使用即可!也可以在set方法上使用
使用@Autowired我们可以不用编写set方法了,前提是你的ioc容器中存在自动装配的属性,且符合byName的名字,如果你想要想要获得指定id的bean,就可以在@Autowired下再使用一个@Qualifiar(value=“想要指定的id”);这样就可以了。
注意:如果使用@Autowired找不到bean就会报错,你可以使用@Autowired(required=false)来实现允许bean为null的情况。
@Resource
默认通过ByName,如果找不到则使用byType,可以使用@Resource(name=“bean的id”)来获取指定的bean。
@Autowired和@Resource的区别
- 都可以放在属性上用来自动装配
- @Autowired通过ByType的方式实现,而且必须要求这个对象存在【常用】
- @Resource默认ByName,如果找不到则ByName。两个都找不到就报错
注意:在spring4之后,想通过注解开发,必须导入aop的包。
注解扫描开启
<!-- 指定要扫描的包,这个包下的注解就会生效。@Bean @Compoment @Controller @Service之类 -->
<context:component-scan base-package="com.mao.pojo"></context:component-scan>
<!-- 注解驱动,有了该配置就可以使用@Autowired @Resource等注解 -->
<context:annotation-config/>
使用注解实战
- 使用@Compoment
package com.mao.pojo;
import org.springframework.stereotype.Component;
@Component
public class User {
public String name = "童胖";
}
使用该注解后就相当于在xml中配置了User的一个类,且会把“童胖”自动注入到其中,然而除了该方法外还有另外的注入方式:
- 属性的注入方式
@Component
public class User {
@Value("童胖")//相当于<property name="name" value="童胖"></property>的配置
private String name ;//成员变量没赋值默认为null
@Value("童胖")//除了上述方式外,该方式也等价于上面的方式
public String getName(){
return name;
}
}
- 衍生的注解
相同的功能但是为了适应MVC开发,衍生了三个注解:
- dao层:@Resposity
- service层:@Service
- controller层:@Controller
- 其他注解
@Scope相当于bean中的scope就是指定作用域的 - 小结
xml与注解:- xml更加万能,适用于任何场合!维护简单方便
- 注解不是自己的类使用不了,维护相对复杂
最佳实践:配置用来管理bean,注解完成属性的注入。
使用Java来配置spring
完全不使用xml,用纯java来配置spring。
在spring之后推荐使用该方式来配置了。
package com.mao.config;
import com.mao.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@ComponentScan("com.mao.pojo")//包扫描
@Import(MaoConfig2.class)//相当于xml中的<import>
//该配置文件就相当于以前的application.xml
public class MaoConfig {
@Bean
//注册一个bean,就相当于我们之前写的一个bean标签
//这个方法的名字就相当于bean标签中的id属性(这里用了user)
//这个方法的返回值就相当于bean标签中的class属性
public User user(){
return new User();
}
}
//需要注意的是@Configuration本身也是一个@Compoment,而想通过配置实现就需要实现的类是ApplicationContext context = new AnnotationConfigApplicationContext(MaoConfig.class);