一、所需依賴
1、Spring核心依賴
2、Spring DAO依賴
3、Spring Web依賴
4、Spring Test依賴
二、XML命名空間
三、IOC
1、什麼是IOC
2、什麼是DI
3、DI的實現方式
3.1、構造器注入
3.2、Setter注入
4、IOC容器
4.1、IOC容器的設計
4.2、ApplicationContext
4.3、註解注入方式
4.3.1、@Autowired 自動裝配的歧義性
4.3.2、@Autowired 爲什麼作用在接口上
一、所需依賴
<!-- Spring依賴 -->
<!-- 1.Spring核心依賴 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!-- 2.Spring dao依賴 -->
<!-- spring-jdbc包括了一些如jdbcTemplate的工具類 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!-- 3.Spring web依賴 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!-- 4.Spring test依賴:方便做單元測試和集成測試 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
1、Spring核心依賴
spring-core、spring-beans、spring-context
2、Spring DAO依賴
spring-jdbc (JDBCTemplate模板)、spring-tx
3、Spring Web依賴
spring-web、spring-webmvc
4、Spring Test依賴
spring-test
二、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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
三、IOC
1、什麼是IOC
“控制反轉”, 將創建對象的過程交給Spring, 比如我們不需要了解Redis或Mybatis的構建過程, 只需簡單的配置即可使用, 又比如多個團隊開發不同組件, 我們不需要其他團隊開發的組件構建過程, 我們這需要的時候直接拿來用即可
2、什麼是DI
“依賴注入” IOC的實現方式
3、DI的實現方式
構造器注入
Setter注入
接口注入
目前最常用的是構造器注入與Setter注入, 接口注入一般是使用第三方API時使用, 底層Spring都是通過反射來實現的, 這個我們後面再討論
3.1、構造器注入
創建 Entity實體類
@Data
public class Users {
private Long id;
private String username;
private String password;
private String email;
public Users(Long id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
}
配置XML
<bean id="users" class="com.chenjiaxin.spring.entity.Users">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="zhangsan"/>
<constructor-arg index="2" value="zhangsan123"/>
<constructor-arg index="3" value="[email protected]"/>
</bean>
3.2、Setter注入
該方式是Spring比較推薦的方式, 優點是靈活性高, 由於當我們構造參數足夠多時, 構造器注入就顯得十分冗餘
首先,默認情況下 要注入的對象必須要有無參構造器
@Data
public class Users {
private Long id;
private String username;
private String password;
private String email;
// 可以省略, 這裏爲了說明
public Users() {
}
}
XML配置
<bean id="users" class="com.chenjiaxin.spring.entity.Users">
<property name="email" value="[email protected]"/>
</bean>
4、IOC容器
從上面的例子中我們知道IOC的作用, 它可以容納我們開發的各種Bean
4.1、IOC容器的設計
IOC容器的設計主要依賴於 BeanFactory與ApplicationContext兩個接口, 其中 ApplicationContext是BeanFactory的子接口, 換就話說
BeanFactory是IOC最底層的接口, 但是工作中我們一般使用 ApplicationContext, 因爲它對BeanFactory的功能又做了許多擴展
- BeanFactory源碼
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
boolean containsBean(String var1);
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
String[] getAliases(String var1);
}
由於這個接口的重要性, 筆者有必要進行一些基本的闡述
- getBean 的多個方法用於獲取配置給Spring IOC容器的Bean, 從參數類型可以看出可以是字符串也可以是Class類型
isSingleton 判斷是否爲單例 true 爲單例 isPrototype 判斷是否爲非單例 true 爲非單例
getAliases 獲取別名
4.2、ApplicationContext
- ApplicationContext源碼
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId(); //獲取ID
String getApplicationName(); //獲取應用名稱
String getDisplayName(); //獲取應用顯示名稱
long getStartupDate(); //獲取應用啓動時間
@Nullable
ApplicationContext getParent(); //獲取父級應用上下文
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; //獲取bean工廠(DefaultListableBeanFactory)
}
4.2.1、ClassPathXmlApplicationContext
會在啓動時加載指定XML配置, 初始化容器, 比如通過上面的 DI進行Setter或構造器注入之後 我們想得到這個Bean可以這樣做
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
Users users = context.getBean("users", Users.class);
System.out.println(users);
}
4.2.2、AnnotationConfigApplicationContext
使用AnnotationConfigApplicationContext可以實現基於Java的配置類加載Spring的應用上下文。避免使用application.xml進行配置。相比XML
配置,更加便捷。
- 創建 configuration配置類
@Configuration註解就相當於XML中的<beans/> 標籤
@Configuration
public class UserConfig {
@Bean
public Users getUsers() {
Users users = new Users();
users.setId(1L);
users.setUsername("lisi");
return users;
}
}
- 讀取該bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(UserConfig.class); //註冊配置類
context.refresh(); //刷新容器
Users bean = context1.getBean(Users.class);
4.3、註解注入方式
組件掃描 @Component && @ComponentScan
自動裝配 @Autowired
註解注入 等同於
組件掃描
- 在POJO類上面添加 @Component 註解
- 添加配置類,使用 @ComponentScan 使用包掃描, 掃描指定包下的 @Component 註解
- 使用 AnnotationConfigApplicationContext類獲取對象
@Component
public class Users{
@Value("1")
private Long id;
@Value("zhangsan")
private String username;
}
@ComponentScan(basePackages = "com.chenjiaxin")
public class UserConfig {
}
public class SpringMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
Users bean = context.getBean(Users.class);
System.out.println(bean);
}
}
組件掃描 只能作用在簡單數據類型之上, 如果要作用在複雜對象上是不可取的, 比如下面的例子
//角色類
@Data
public class Role {
private Long id;
private String roleName;
}
//用戶類
@Data
public class Users{
private String email;
private Role role;
}
//XML
<bean id="role" class="com.chenjiaxin.spring.entity.Role">
<property name="id" value="1"/>
<property name="roleName" value="管理員"/>
</bean>
<bean id="users" class="com.chenjiaxin.spring.entity.Users">
<property name="email" value="[email protected]"/>
<property name="role" ref="role"/>
</bean>
//獲取對象
public class SpringMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
Users bean = context.getBean(Users.class);
System.out.println(bean);
}
}
@Autowired 自動裝配 原理是Set注入, 對上方測試代碼進行改造
//角色POJO
@Data
@Component
public class Role {
@Value("1")
private Long id;
@Value("管理員")
private String roleName;
}
//用戶POJO
@Data
@Component
public class Users{
@Autowired
private Role role;
@Value("[email protected]")
private String email;
}
//配置註解掃描
@ComponentScan(basePackages = "com.chenjiaxin")
public class UserConfig {
}
//測試
public class SpringMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
Users bean = context.getBean(Users.class);
System.out.println(bean);
}
}
@Autowired 是按照類型 獲取Bean的
public interface BeanFactory {
...
<T> T getBean(Class<T> var1) throws BeansException;
...
}
4.3.1、@Autowired 自動裝配的歧義性
先看下面一個例子, Uservice接口有兩個實現類, 在Test中 使用Autowired 會出現歧義性
public interface UserService {
// 讀取數據庫僞代碼業務接口
Users selectOne();
}
//實現類一
@Service
public class UserServiceImpl implements UserService {
...
}
//實現類二
@Service
public class UserServiceImplTwo implements UserService {
...
}
//測試類
@RunWith(SpringRunner.class)
@ContextConfiguration(classes=UserConfig.class)
public class SpringMain {
@Autowired
private UserService userService;
@Test
public void test1() {
System.out.println(userService.selectOne());
}
}
解決方案:
- @Primary
- @Qualifier
方式一: 被 @Primary標註的實現類 ,當spring 進行裝配時 會被優先處理。
@Service
@Primary
public class UserServiceImpl implements UserService {
...
}
方式二: 也可以在裝配的時候 強制讓spring 按照名稱進行裝配 也就是XML中bean標籤的ID
@Autowired
@Qualifier("userServiceImpl")
private UserService userService;
4.3.2、@Autowired 爲什麼作用在接口上
如果Spring配置了<context:component-scan base-package=“com.*.service”></context:component-scan>,並且要注入的接口只有一個實現類的話,那麼spring框架可
以自動將interface與其實現類組裝起來。如果沒有配置component scan,那麼我們必須在application-config.xml(或等同的配置文件)定義這個bean。
一般情況下一個接口我們只寫一個實現類,這個時候我們只需要在實現類上註解@service
@Service
public class UserServiceImpl implements UserService {
……
}
在這種情況下,我們要使用這個實現類的時候也只需要用@Autowired即可 Spring會自動組裝userservice與其實現類UserServiceImpl
@Autowired
private Userservice userservice;