Xin chào! Trong khi quản trị JavaRush đang làm việc ở các cấp độ mới, tôi muốn bắt đầu một loạt bài viết đào tạo về Spring Framework. Vâng, tôi biết rằng đã có rất nhiều tài liệu về chủ đề này trên Internet, nhưng, như thực tế cho thấy, tất cả chúng đều ở cấp độ Hello World. Tôi muốn nói không phải về cách đặt chú thích một cách chính xác mà về cách tất cả hoạt động “dưới mui xe”. Bài viết dành cho những người đã làm việc với framework này bằng cách này hay cách khác và đã quen thuộc với các khái niệm cơ bản.
Thực tế là một Bean không nhất thiết phải là một lớp logic nghiệp vụ cho ứng dụng của bạn. Bean còn được gọi là đậu cơ sở hạ tầng. Nói tóm lại, một cơ sở hạ tầng là một lớp cấu hình các đậu logic nghiệp vụ của bạn (vâng, có quá nhiều đậu). Tôi sẽ cho bạn biết thêm về nó bên dưới, nhưng để hiểu rõ hơn một chút về cấu hình chính xác của BPP, tôi sẽ đưa ra một ví dụ. Mọi người có quen thuộc với bản tóm tắt không
Đang khởi tạo bối cảnh.
Vì vậy, hãy bắt đầu với những điều cơ bản. Theo tôi, một trong những điểm quan trọng nhất là hiểu cách thiết lập bối cảnh và khởi tạo các đậu. Như bạn đã biết, trước khi Spring bắt đầu hoạt động, nó cần được cấu hình. Vào thời xa xưa, việc này được thực hiện bằng cách sử dụng các tệp xml (trên một số dự án, chủ yếu là các dự án cũ, họ vẫn tiếp tục làm điều này cho đến ngày nay). Đây là một ví dụ nhỏ về tệp cấu hình như vậy:<?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-3.0.xsd">
<bean id="helloWorld" class="ru.javarush.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
Nhìn chung, điều này là đủ để tạo một vài bộ điều khiển và khởi động quá trình khởi động (sẽ không thành công). Nhưng cấu hình này sẽ khiến Spring hoạt động như thế nào? Và đây là nơi mọi thứ trở nên thú vị. Để Spring hiểu được cấu hình của chúng tôi, có một tệp XmlBeanDefinitionReader
. BeanDefinition
Đây là một thành phần Spring nội bộ có chức năng quét (phân tích cú pháp) xml và tạo các tệp dựa trên những gì chúng tôi đã viết ở đó . BeanDefinition
là một đối tượng lưu trữ thông tin về đậu. Điều này bao gồm: nó (bean) sẽ được tạo từ lớp nào; phạm vi; liệu khởi tạo lười biếng có được cài đặt hay không; Có cần thiết phải khởi tạo một thuộc tính khác và các thuộc tính khác được mô tả trong xml trước đậu này không. Tất cả các nhận được BeanDefinition
đều được thêm vào HashMap
, trong đó mã định danh là tên của Bean (do bạn đặt hoặc do Spring gán) và BeanDefinition
chính đối tượng đó. Sau khi mọi thứ BeanDefinition
được tạo ra, một anh hùng mới xuất hiện trên sân khấu - BeanFactory
. Đối tượng này lặp lại HashMap’e
s BeanDefinition
, tạo các hạt dựa trên chúng và đặt chúng vào vùng chứa IoC. Trên thực tế, có một sắc thái ở đây, khi ứng dụng khởi động, IoC container sẽ chứa các Bean có phạm vi Singleton (được đặt theo mặc định), trong khi phần còn lại được tạo khi cần thiết (prototype, request, session). Và bây giờ lạc đề một chút, chúng ta hãy làm quen với một nhân vật khác.
Gặp gỡ BeanPostProcessor. (BPP)
![bộ xử lý bài đậu](https://cdn.javarush.com/images/article/c7086349-9c05-4e77-b8eb-8eddbcc6306c/1024.jpeg)
@Autowired
? Vì vậy, bạn AutowiredAnnotationBeanPostProcessor
có trách nhiệm đảm bảo rằng tất cả các lớp của bạn được nhúng vào nhau. ![ý nghĩa của uknow](https://cdn.javarush.com/images/article/e4313405-c16d-44f6-b695-a9f288963e5e/original.jpeg)
Hãy quay trở lại BeanFactory
Bây giờ đã biết về BPP, bạn cần làm rõ rằng khi lặp quaHashMap
các 's, BeanDefinition
tất cả các 's trước tiên được tạo và đặt riêng biệt (không phải trong vùng chứa IoC) BeanPostProcessor
. Sau đó, các Bean thông thường trong logic nghiệp vụ của chúng tôi sẽ được tạo, đưa vào bộ chứa IoC và cấu hình của chúng bắt đầu sử dụng các BPP trì hoãn riêng biệt. Và đây là cách nó diễn ra, mỗi BPP có 2 phương thức:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Lặp lại các thùng của chúng tôi hai lần. Lần đầu tiên phương thức được gọi postProcessorBeforeInitialization
và lần thứ hai phương thức được gọi postProcessorAfterInitialization
. Chắc chắn câu hỏi đã được đặt ra là tại sao lại cần đến hai phương pháp, hãy để tôi giải thích. Thực tế là để xử lý một số chú thích (chẳng hạn như @Transactional
, chẳng hạn), Bean của chúng tôi được thay thế bằng một lớp proxy. Để hiểu lý do tại sao điều này được thực hiện, bạn cần biết nó hoạt động như thế nào @Transactional
và đây là cách nó hoạt động. Bạn cần nhanh chóng thêm một vài dòng mã vào phương thức được đánh dấu bằng chú thích này. Làm thế nào để làm nó? Đúng vậy, bằng cách tạo một lớp proxy, bên trong đó mã cần thiết sẽ được thêm vào phương thức được yêu cầu. Bây giờ hãy tưởng tượng tình huống này, chúng ta có một lớp:
class A {
@Autowired
private SomeClass someClass;
@Transactional
public void method() {
// модификатор доступа обязательно public
}
}
Lớp này có 2 chú thích @Autowired
và @Transactional
. Cả hai chú thích đều được xử lý bởi các BPP khác nhau. Nếu nó hoạt động trước AutowiredBPP
thì mọi thứ sẽ ổn, nhưng nếu không, chúng ta sẽ gặp phải vấn đề này. Thực tế là khi lớp proxy được tạo, tất cả thông tin meta sẽ bị mất. Nói cách khác, sẽ không có thông tin về chú thích @Autowired
trong lớp proxy và do đó AutowiredBPP
nó sẽ không hoạt động, điều đó có nghĩa là trường của chúng ta someClass
sẽ có giá trị null
, rất có thể sẽ dẫn đến NPE. Cũng cần biết rằng giữa các lệnh gọi phương thức, -method postProcessorBeforeInitialization
sẽ được postProcessorAfterInitialization
gọi init
, nếu có. Về cơ bản, đây là hàm tạo thứ hai, nhưng điểm khác biệt là tại thời điểm này, tất cả các phần phụ thuộc của chúng ta đã được nhúng vào lớp và chúng ta có thể truy cập chúng từ init
phương thức -. Vì vậy, một lần nữa thuật toán khởi tạo ngữ cảnh:
XmlBeanDefinitionReader
quét tệp cấu hình xml của chúng tôi.- Tạo
BeanDefinition
và đặt chúng vàoHashMap
. - Đến
BeanFactory
và từ đâyHashMap
riêng biệt cộng lại tất cả cácBeanPostProcessor
's. - Tạo
BeanDefinition
các hạt từ các và đặt chúng vào vùng chứa IoC. - Ở đây các BPP đến và định cấu hình các loại đậu này bằng 2 phương pháp.
- Sẵn sàng.
GO TO FULL VERSION