Spring 原始碼詳解(一)
一、所需依賴
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="18297828@sinl.com"/>
</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="18297828@sinl.com"/>
</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="18297828@sinl.com"/>
<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("981928@sign.com")
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;
相關文章
- Spring原始碼之九finishRefresh詳解Spring原始碼
- Spring原始碼系列(補充):詳解ApplicationContextSpring原始碼APPContext
- shiro 整合 spring 實戰及原始碼詳解Spring原始碼
- spring-MVC原始碼解讀(一)SpringMVC原始碼
- Spring原始碼剖析7:AOP實現原理詳解Spring原始碼
- 【詳解】ThreadPoolExecutor原始碼閱讀(一)thread原始碼
- Spring原始碼系列(一)--詳細介紹bean元件Spring原始碼Bean元件
- Spring原始碼分析之Bean的建立過程詳解Spring原始碼Bean
- Caddy 原始碼閱讀(一)Run 詳解原始碼
- Spring:原始碼解讀Spring IOC原理Spring原始碼
- 5.1 Spring5原始碼--Spring AOP原始碼分析一Spring原始碼
- ProgressHUD原始碼詳解原始碼
- HashMap原始碼詳解HashMap原始碼
- redux 原始碼詳解Redux原始碼
- TimSort原始碼詳解原始碼
- Spring Aop 詳解一Spring
- spring原始碼解讀-aopSpring原始碼
- Spring原始碼剖析5:JDK和cglib動態代理原理詳解Spring原始碼JDKCGLib
- 【Redis原始碼】Redis 6 ACL原始碼詳解Redis原始碼
- Spring原始碼之IOC(一)BeanDefinition原始碼解析Spring原始碼Bean
- LinkedList詳解-原始碼分析原始碼
- ArrayList詳解-原始碼分析原始碼
- 劍指Spring原始碼(一)Spring原始碼
- Spring事務原始碼解讀Spring原始碼
- Spring原始碼分析——搭建spring原始碼Spring原始碼
- 微服務生態元件之Spring Cloud OpenFeign詳解和原始碼分析微服務元件SpringCloud原始碼
- 微服務生態元件之Spring Cloud LoadBalancer詳解和原始碼分析微服務元件SpringCloud原始碼
- Spring Boot Transactional註解原始碼閱讀筆記(一)Spring Boot原始碼筆記
- React Scheduler 原始碼詳解(1)React原始碼
- ArrayMap詳解及原始碼分析原始碼
- LeakCanary詳解與原始碼分析原始碼
- EventBus詳解及原始碼分析原始碼
- React Scheduler 原始碼詳解(2)React原始碼
- MapReduce 詳解與原始碼分析原始碼
- 詳解HashMap原始碼解析(下)HashMap原始碼
- 詳解HashMap原始碼解析(上)HashMap原始碼
- Spring原始碼分析之IoC(一)Spring原始碼
- Spring原始碼解析之BeanFactoryPostProcessor(一)Spring原始碼Bean