iT邦幫忙

2021 iThome 鐵人賽

DAY 5
0

一般而言,網站程式大多會是這樣的架構:
https://ithelp.ithome.com.tw/upload/images/20210919/20128973GkwYpGQIUY.png
https://developer.mozilla.org/en-US/docs/Glossary/MVC

就是大家所熟知的MVC

這次實作的是前後端分離
因此View的部分先不管,專心弄Model跟Controller

昨天已經建立了User的entity跟repository
今天來做service

建立一個UserService.java

@Service
@RequiredArgsConstructor
public class UserService {
    
    private final UserRepo userRepo;

    public List<User> getAllUsers(){
        return userRepo.findAll();
    }
    public Optional<User> getOneUser(String email){
        return userRepo.findUserByEmail(email);
    }
    public void addUser(User user){
        userRepo.insert(user);
    }
}

在這支程式中我用了兩個annotation

@Service 
@RequiredArgsConstructor

@Service是用來標記這是一個Service層的class,
Spring會將其建立並納入Spring Container內等待調用
藉此達到控制反轉(IoC)的效果

相似的annotation還有以下幾樣
@Repository
@Service
@Controller
這些全都是@Component的子延伸,目的都是建立物件丟到Spring Container裡面

@RequiredArgsConstructor則lombok的annotation,跟剛剛spring boot的annotation沒有關係
透過它可以在程式中自動建立建構子並且只包含定義為final的變數
也就是剛剛程式裡面的
private final UserRepo userRepo;
相似的有@AllArgsConstructor、@NorgsConstructor就不再多做解釋了

如果沒用@RequiredArgsConstructor的話
就要自己寫建構子了:

    public UserService(UserRepo userRepo){
        this.userRepo=userRepo;
    }

而這段又等同於

	@Autowired
    public UserService(UserRepo userRepo){
        this.userRepo=userRepo;
    }

因為在Spring4.3後的版本,對於只有一個建構子的情況下,
Spring 會自動幫你尋找Spring Container中是否有相配的bean,所以不用再加@Autowored

雖然也可以直接寫

@Autowired 
private UserRepo userRepo;

這種寫法叫Field Injection,很方便,
但這樣的做法在特定情況下可能會造成程式執行時物件還沒被注入導致nullpointerException
而且會提高這個class跟spring容器的耦合,可能會不好做單元測試
總之是官方不建議的寫法,

而我最初的寫法叫作Constructor Injection,是以建構子來注入的做法

還有另一種注入叫做Setter Injection,看起來就比較少人用,有興趣的人可以再深入研究看看

最後再做個小補充,
Spring是將有相關註解(@Component、@Repository...etc)
的class在Spring初始執行時註冊為一個Bean,
然後放到Spring Container內,
當有其他程式需要使用時
可以使用**@Autowired**註解來直接取用Spring Container中相對應的bean,
就不用再自己new一個物件了

但是我在UserRepo沒有下@Repository的註解呀
為什麼@Autowired能夠調用的到UserRepo呢?

這是因為UserRepo繼承了MongoRepository
而其底層繼承了Repository
只要繼承Repository,Spring就會自動為其裝配為一個bean,因此我們不用定義@Repository
程式就能在Spring Container中找到UserRepo。

這樣層層繼承下來,不會因此而讓每個介面都被裝配成bean嗎
UserRepo←MongoRepository←PagingAndSortingRepository←CrudRepository←Repository
https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/repository/MongoRepository.html

因為這些介面都有定義@NoRepositoryBean,告訴Spring這些介面沒有要被做成bean
所以沒這個問題。

第5天了,原本想利用連假多寫幾天的稿備用,但是光是查文件就花了好多時間...
雖然Spring Boot寫起來容易,但背後要懂的知識點還真是不少...
/images/emoticon/emoticon20.gif


上一篇
[Day 04] - 用Spring Boot連接Mongo DB
下一篇
[Day 06] - 用Spring Boot 建立Controller
系列文
30天全端挑戰!React+Spring Boot+Mongo DB 串接永豐API 打造金融網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言