前言
華夏ERP基于SpringBoot框架和SaaS模式,立志為中小企業(yè)提供開源好用的ERP軟件,目前專注進(jìn)銷存+財(cái)務(wù)+生產(chǎn)功能。主要模塊有零售管理、采購(gòu)管理、銷售管理、倉(cāng)庫(kù)管理、財(cái)務(wù)管理、報(bào)表查詢、系統(tǒng)管理等。支持預(yù)付款、收入支出、倉(cāng)庫(kù)調(diào)撥、組裝拆卸、訂單等特色功能。擁有庫(kù)存狀況、出入庫(kù)統(tǒng)計(jì)等報(bào)表。同時(shí)對(duì)角色和權(quán)限進(jìn)行了細(xì)致全面的控制,精確到每個(gè)按鈕和菜單。
項(xiàng)目總述
- 很多人說華夏ERP(英文名:jshERP)是目前人氣領(lǐng)先的國(guó)產(chǎn)ERP系統(tǒng)
- 雖然目前只有進(jìn)銷存+財(cái)務(wù)+生產(chǎn)的功能,但后面會(huì)推出ERP的全部功能,有興趣請(qǐng)幫點(diǎn)一下 Star 哦
- 演示地址:http://47.116.69.14 演示賬號(hào):jsh,密碼:123456
開發(fā)初衷
- 華夏ERP立志為中小企業(yè)提供開源好用的ERP軟件,降低企業(yè)的信息化成本
- 個(gè)人開發(fā)者也可以使用華夏ERP進(jìn)行二次開發(fā),加快完成開發(fā)任務(wù) 關(guān)注Java項(xiàng)目分享
- 初學(xué)JAVA的小伙伴可以下載源代碼來進(jìn)行學(xué)習(xí)交流
技術(shù)框架
- 核心框架:SpringBoot 2.0.0
- 持久層框架:Mybatis 1.3.2
- 日志管理:Log4j 2.10.0
- JS框架:Jquery 1.8.0
- UI框架: EasyUI 1.9.4
- 模板框架: AdminLTE 2.4.0
- 項(xiàng)目管理框架: Maven 3.2.3
- API接口框架: swagger2.7.0(ip:port/doc.html)
開發(fā)環(huán)境
建議開發(fā)者使用以下環(huán)境,可以避免版本不一致帶來的問題
- IDE: IntelliJ IDEA 2017+
- DB: Mysql5.7+
- JDK: JDK1.8
- Maven: Maven3.2.3+
服務(wù)器環(huán)境
- 數(shù)據(jù)庫(kù)服務(wù)器:Mysql5.7+
- JAVA平臺(tái): JRE1.8
- 操作系統(tǒng):Windows、Linux等
開源說明
- 本系統(tǒng)100%開源,遵守GPL-3.0協(xié)議
系統(tǒng)美圖
- 首頁(yè)
- 零售管理
- 采購(gòu)管理
- 銷售管理
- 倉(cāng)庫(kù)管理
- 財(cái)務(wù)管理
- 報(bào)表查詢
- 商品管理
- 基本資料
- 系統(tǒng)管理
源碼資料獲取方式:關(guān)注小編+轉(zhuǎn)發(fā)文章+私信【 0626】免費(fèi)獲?。。。?!
一、什么是Spring?談?wù)勀銓?duì)IOC和AOP的理解。
Spring: 是一個(gè)企業(yè)級(jí)java應(yīng)用框架,他的作用主要是簡(jiǎn)化軟件的開發(fā)以及配置過程,簡(jiǎn)化項(xiàng)目部署環(huán)境。Spring的有點(diǎn):1、Spring低侵入設(shè)計(jì),對(duì)業(yè)務(wù)代碼的污染非常低。2、Spring的DI機(jī)制將對(duì)象之間的關(guān)系交由框架處理,減少組件的耦合。3、Spring提供了AOP技術(shù),支持將一些通用的功能進(jìn)行集中式管理,從而提供更好的復(fù)用。4、Spring對(duì)于主流框架提供了非常好的支持。IOC就是控制反轉(zhuǎn),指創(chuàng)建對(duì)象的控制權(quán)轉(zhuǎn)移給Spring來進(jìn)行管理。簡(jiǎn)單來說,就是應(yīng)用不用去new對(duì)象了,而全部交由Spring自動(dòng)生產(chǎn)。IOC有三種注入方式:1、 構(gòu)造器注入 2、setter方法注入 3、根據(jù)注解注入。AOP 面向切面。用于將那些與業(yè)務(wù)無(wú)關(guān),但卻能對(duì)多個(gè)對(duì)象產(chǎn)生影響的公共行為。抽取并封裝成一個(gè)可重用的模塊。AOP的核心就是動(dòng)態(tài)代理。JDK的動(dòng)態(tài)代理 和CGLIB動(dòng)態(tài)代理。
二、Spring容器的啟動(dòng)流程是怎么樣的?
使用AnnotationConfigApplicationContext 來跟蹤一下啟動(dòng)流程: this(); 初始化reader和scannerscan(basePackages); 使用scanner組件掃描basePackage下的所有對(duì)象,將配置類的BeanDefinition注冊(cè)到容器中。refresh(); 刷新容器。prepareRefresh 刷新前的預(yù)處理obtainFreshBeanFactory: 獲取在容器初始化時(shí)創(chuàng)建的BeanFactoryprepareBeanFactory: BeanFactory的預(yù)處理工作,會(huì)向容器中添加一些組件。postProcessBeanFactory: 子類重寫該方法,可以實(shí)現(xiàn)在BeanFactory創(chuàng)建并預(yù)處理完成后再做進(jìn)一步的設(shè)置。invokeBeanFactoryPostProcessors: 在BeanFactory初始化之后執(zhí)行BeanFactory的后處理器。
registerBeanPostProcessors: 向容器中注冊(cè)Bean的后處理器,他的主要作用就是干預(yù)Spring初始化Bean的流程,完成代理、自動(dòng)注入、循環(huán)依賴等這些功能。initMessageSource: 初始化messagesource組件,主要用于國(guó)際化。initApplicationEventMulticaster: 初始化事件分發(fā)器onRefresh: 留給子容器,子類重寫的方法,在容器刷新的時(shí)候可以自定義一些邏輯。registerListeners: 注冊(cè)監(jiān)聽器。finishBeanFactoryInitialization: 完成BeanFactory的初始化,主要作用是初始化所有剩下的單例Bean。finishRefresh: 完成整個(gè)容器的初始化,發(fā)布BeanFactory容器刷新完成的事件。
三、Spring框架中Bean的創(chuàng)建過程是怎樣
的?首先,簡(jiǎn)單來說,Spring框架中的Bean經(jīng)過四個(gè)階段: 實(shí)例化 -》 屬性賦值 -》初始化 -》 銷毀然后: 具體來說,Spring中Bean 經(jīng)過了以下幾個(gè)步驟:1、實(shí)例化: new xxx(); 兩個(gè)時(shí)機(jī): 1、當(dāng)客戶端向容器申請(qǐng)一個(gè)Bean時(shí),2、當(dāng)容器在初始化一個(gè)Bean時(shí)發(fā)現(xiàn)還需要依賴另一個(gè)Bean。 BeanDefinition 對(duì)象保存。-到底是new一個(gè)對(duì)象還是創(chuàng)建一個(gè)動(dòng)態(tài)代理?2、設(shè)置對(duì)象屬性(依賴注入):Spring通過BeanDefinition找到對(duì)象依賴的其他對(duì)象,并將這些對(duì)象賦予當(dāng)前對(duì)象。3、處理Aware接口:Spring會(huì)檢測(cè)對(duì)象是否實(shí)現(xiàn)了xxxAware接口,如果實(shí)現(xiàn)然后,就會(huì)調(diào)用對(duì)應(yīng)的方法。BeanNameAware、BeanClassLoaderAware、BeanFactoryAware、ApplicationContextAware
4、BeanPostProcessor前置處理: 調(diào)用BeanPostProcessor的postProcessBeforeInitialization方法5、InitializingBean: Spring檢測(cè)對(duì)象如果實(shí)現(xiàn)了這個(gè)接口,就會(huì)執(zhí)行他的afterPropertiesSet()方法,定制初始化邏輯。6、init-method: 如果Spring發(fā)現(xiàn)Bean配置了這個(gè)屬性,就會(huì)調(diào)用他的配置方法,執(zhí)行初始化邏輯。@PostConstruct7、BeanPostProcessor后置處理: 調(diào)用BeanPostProcessor的postProcessAfterInitialization方法
到這里,這個(gè)Bean的創(chuàng)建過程就完成了, Bean就可以正常使用了。
8、DisposableBean: 當(dāng)Bean實(shí)現(xiàn)了這個(gè)接口,在對(duì)象銷毀前就會(huì)調(diào)用destory()方法。9、destroy-method: @PreDestroy
四、Spring框架中的Bean是線程安全的嗎?
如果線程不安全,要如何處理?Spring容器本身沒有提供Bean的線程安全策略,因此,也可以說Spring容器中的Bean不是線程安全的。要如何處理線程安全問題,就要分情況來分析。Spring中的作用域: 1、 sington 2、prototype: 為每個(gè)Bean請(qǐng)求創(chuàng)建給實(shí)例。3、request:為每個(gè)request請(qǐng)求創(chuàng)建一個(gè)實(shí)例,請(qǐng)求完成后失效。 4、 session:與request是類似的。 5、global-session:全局作用域。對(duì)于線程安全問題:1> 對(duì)于prototype作用域,每次都是生成一個(gè)新的對(duì)象,所以不存在線程安全問題。2>sington作用域: 默認(rèn)就是線程不完全的。但是對(duì)于開發(fā)中大部分的Bean,其實(shí)是無(wú)狀態(tài)的,不需要保證線程安全。所以在平常的MVC開發(fā)中,是不會(huì)有線程安全問題的。
無(wú)狀態(tài)表示這個(gè)實(shí)例沒有屬性對(duì)象, 不能保存數(shù)據(jù),是不變的類。比如: controller、service、dao有狀態(tài)表示示例是有屬性對(duì)象,可以保存數(shù)據(jù),是線程不安全的, 比如pojo.但是如果要保證線程安全,可以將Bean的作用域改為prototype 比如像 ModelView。另外還可以采用ThreadLocal來解決線程安全問題。ThreadLocal為每個(gè)線程保存一個(gè)副本變量, 每個(gè)線程只操作自己的副本變量。
五、Spring如何處理循環(huán)依賴問題?
循環(huán)依賴: 多個(gè)對(duì)象之間存在循環(huán)的引用關(guān)系,在初始化過程當(dāng)中,就會(huì)出現(xiàn)”先有蛋還是先有雞”的問題。
一種是使用@Lazy注解: 解決構(gòu)造方法造成的循環(huán)依賴問題另一種是使用三級(jí)緩存一級(jí)緩存:緩存最終的單例池對(duì)象: private final MapsingletonObjects = new ConcurrentHashMap(256);二級(jí)緩存:緩存初始化的對(duì)象:private final MapearlySingletonObjects = new ConcurrentHashMap(16);三級(jí)緩存:緩存對(duì)象的ObjectFactory: private final Map singletonFactories = new HashMap(16);
對(duì)于對(duì)象之間的普通引用,二級(jí)緩存會(huì)保存new出來的不完整對(duì)象,這樣當(dāng)單例池中找到不依賴的屬性時(shí),就可以先從二級(jí)緩存中獲取到不完整對(duì)象,完成對(duì)象創(chuàng)建建,在后續(xù)的依賴注入過程中,將單例池中對(duì)象地引用關(guān)系調(diào)整完成。三級(jí)緩存:如果引用的對(duì)象配置了AOP,那在單例池中最終就會(huì)需要注入動(dòng)態(tài)代理對(duì)象,而不是原對(duì)象。而生成動(dòng)態(tài)代理是要在對(duì)象初始化完成之后才開始的。于是Spring增加三級(jí)緩存,保存所有對(duì)象的動(dòng)態(tài)代理配置信息。在發(fā)現(xiàn)有循環(huán)依賴時(shí),將這個(gè)對(duì)象的動(dòng)態(tài)代理信息獲取出來,提前進(jìn)行AOP,生成動(dòng)態(tài)代理。核心代碼就在DefaultSingletonBeanRegistry的getSingleton方法當(dāng)中。
protected Object getSingleton(String beanName, boolean allowEarlyReference){// Quick check for existing instance without full singleton lockObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null &&isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within fullsingleton locksingletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject =this.earlySingletonObjects.get(beanName);if (singletonObject == null) {ObjectFactory singletonFactory =this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject =singletonFactory.getObject();this.earlySingletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName}}}}}return singletonObject;}
六、Spring如何處理事務(wù)?
Spring當(dāng)中支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式:1、編程式事務(wù)可以使用TransactionTemplate。2、聲明式事務(wù): 是Spring在AOP基礎(chǔ)上提供的事務(wù)實(shí)現(xiàn)機(jī)制。他的最大優(yōu)點(diǎn)就是不需要在業(yè)務(wù)代碼中添加事務(wù)管理的代碼,只需要在配置文件中做相關(guān)的事務(wù)規(guī)則聲明就可以了。但是聲明式事務(wù)只能針對(duì)方法級(jí)別,無(wú)法控制代碼級(jí)別的事務(wù)管理理。Spring中對(duì)事務(wù)定義了不同的傳播級(jí)別: Propagation1、 PROPAGATION_REQUIRED:默認(rèn)傳播行為。 如果當(dāng)前沒有事務(wù),就創(chuàng)建一新事務(wù),如果當(dāng)前存在事務(wù),就加入到事務(wù)中。2、PROPAGATION_SUPPORTS: 如果當(dāng)前存在事務(wù),就加入到該事務(wù)。如果當(dāng)前不存在事務(wù),就以非事務(wù)的方式運(yùn)行。
3、PROPAGATION_MANDATORY: 如果當(dāng)前存在事務(wù),就加入該事務(wù)。如果當(dāng)前不存在事務(wù),就拋出異常。
4、PROPAGATION_REQUIRES_NEW: 無(wú)論當(dāng)前存不存在事務(wù),都創(chuàng)建新事務(wù)進(jìn)行執(zhí)行。
5、PROPAGATION_NOT_SUPPORTED: 以非事務(wù)方式運(yùn)行。如果當(dāng)前存在事務(wù)必,就將當(dāng)前事務(wù)掛起。
6、PROPAGATION_NEVER : 以非事務(wù)的方式運(yùn)行。如果當(dāng)前存在事務(wù),就拋出異議常。
7、PROPAGATION_NESTED: 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行;如果當(dāng)前沒有事務(wù),則按REQUEIRED屬性執(zhí)行。Spring中事務(wù)的隔離級(jí)別:1、ISOLATION_DEFAULT: 使用數(shù)據(jù)庫(kù)默認(rèn)的事務(wù)隔離級(jí)別。2、ISOLATION_READ_UNCOMMITTED: 都未提交。允許事務(wù)在執(zhí)行過程中,必須取其他事務(wù)未提交的數(shù)據(jù)。3、ISOLATION_READ_COMMITTED: 讀已提交。允許事務(wù)在執(zhí)行過程中,讀取其他事務(wù)已經(jīng)提交的數(shù)據(jù)。4、ISOLATION_REPEATABLE_READ: 可重復(fù)讀。 在同一個(gè)事務(wù)內(nèi),任意時(shí)刻的查詢結(jié)果是一致的。5、ISOLATION_SERIALIZABLE: 所有事務(wù)依次執(zhí)行。
七、SpringMVC中的控制器是不是單例模
式?如果是,如何保證線程安全?控制器是單例模式。單例模式下就會(huì)有線程安全問題。Spring中保證線程安全的方法1、將scop設(shè)置成非singleton。 prototype, request。2、最好的方式是將控制器設(shè)計(jì)成無(wú)狀態(tài)模式。在控制器中,不要攜帶數(shù)據(jù)。但是可以引用無(wú)狀態(tài)的service和dao。