Spring intervju pitanja, 41 Spring pitanja (33.000 reči, 180 crteža), neophodno za kandidate

Uvod
33.000 reči 180 crteža, detaljno objašnjeno 41 najčešćih Spring intervju pitanja, nakon što učenik nauči ova Spring pitanja, ovaj put će pretući intervjutera, mislim da je sigurno (ručni dog). Organizovao: Chenmo Wang Er, kliknilink za preuzimanje, autor: Sanfen'e, kliknilink za original.
Svetla verzija je pogodnija za štampanje, što je i način koji mnogi studenti vole, štampanje učinkovitije učenje.

Od 15. juna 2025. godine počeo sam sa radom na drugom izdanju, trajalo je dva meseca, uglavnom zato što sam u međuvremenu posvetio puno pažnje Pai Smart RAG projektuza pisanje tutorijala, u drugom izdanju nadogradili smo mnogo sadržaja.
- Za najčešća pitanja, označićemo gde se pojavljuju u "Vodiču za Java intervju (plaćeno)", koja firma, kakvo je originalno pitanje, i dodatiemo 🌟, sadržaj je jasan; ako želiš da uštediš vreme, možeš prvo naučiti ova pitanja, brzo saznati ko si i šta radite, stotinu borbi bez poraza.
- Razlikujemo izvorne odgovore na pitanja i objašnjenja principa, da biste znali zašto i kako, ali i efikasno odgovarali na intervjuu.
- Kombinujemo projekte (Tehnički stil, pmhub) da organizujemo jezik, tako da intervjuter može maksimalno da oseti tvoje iskrenost, a ne mehaničko učenje.
- Popravljamo probleme koji su se pojavili u prvom izdanju, uključujući povratne informacije prijatelja iz porodice, komentare sa sekcije za komentare na sajtu, kao i issue iz GitHub repozitorijuma, da bi ovaj vodič za intervju bio kompletniji.
- Dodajemo neke ponude koje su dobili prijatelji iz Ergeovog programerskog planeta, zahvalnost na kandidatima, i neke priznanja za izmenu životopisa, kako bismo motivisali sve i dali im više samopouzdanja.
- Optimizujemo izgled, dodajemo crteže, reorganizujemo odgovore, da bi bili više konversacioni, i bliže očekivanjima intervjutera.

Stavio sam Ergeov napredni Java put, napredni JVM put, napredni put konkurentnog programiranja, i sve verzije kandidata uključio, pokrivajući Java osnove, Java kolekcije, Java konkurentnost, JVM, Spring, MyBatis, računarske mreže, operativne sisteme, MySQL, Redis, RocketMQ, distribuirane sisteme, mikroservise, dizajn patern,, Linux itd. 16 velikih tema, ukupno preko 400.000 reči, 2000+ crteža, može se reći da je iskreno.
Pokažimo tamnu verziju PDF-a, izgled je jasan, font je elegantan, pogodniji za noćno čitanje, noću je ugodnije za čitanje.

Osnove
1.Šta je Spring?
Spring je Java okvir za razvoj pozadinskog (backend) softvera, njegova najvažnija uloga je da nam pomaže da upravljamo Java objektima.

Njegova najvažnija karakteristika je IoC, odnosno Inversion of Control (inverzija kontrole). Ranije smo za korišćenje objekta morali sami da ga new-ujemo. Ali sa Spring-om, treba samo da kažemo Spring-u koji objekat nam treba, on će automatski napraviti i ubaciti u Spring kontejner.
Na primer, u jednoj Service klasi mi treba Dao objekat, treba samo da dodam @Autowired anotaciju, Spring će automatski ubaciti Dao objekat u Spring kontejner, tako da ne moramo ručno da upravljamo zavisnostima između ovih objekata.

Pored toga, Spring nudi i AOP, odnosno Aspect-Oriented Programming (programiranje orijentisano na aspekte), posebno korisno kada trebamo da radimo neke opšte funkcionalnosti, na primer logging, provera dozvola, upravljanje transakcijama itd. ne moramo u svakoj metodi da pišemo ponavljajući kod, direktno koristimo AOP da zajednički obradimo.

Spring ekosistem je posebno bogat, Spring Boot nam omogućava brzo postavljanje projekta, Spring MVC nam pomaže da obradimo web zahteve, Spring Data pojednostavljuje rad sa bazama podataka, Spring Cloud pomaže nam da radimo mikroservis arhitekturu itd.
Koje karakteristike Spring ima?
Spring karakteristika je prilično mnogo, ja ću reći za nekoliko koje se najviše koriste u stvarnom radu/učenju.

Prvo i najosnovnije je IoC inverzija kontrole i DI ubacivanje zavisnosti, dajući Spring-u mogućnost da nam pomaže u upravljanju kreiranjem objekata i zavisnostima.
Na primer, napišem UserService, treba mi UserDao, ranije bi morao sam da new-ujem UserDao, sada treba samo da dodam @Service anotaciju na UserService, i @Autowired anotaciju na UserDao polju, Spring će automatski obraditi te zavisnosti.
Tako se smanjuje spreznost (coupling) koda, testiranje je lakše za mock.
Drugo je AOP programiranje orijentisano na aspekte. Ovo je posebno korisno kada obrađujemo neke transversalne tačke, na primer ako hoćemo da dodamo kontrolu prava na određene Controller metode, bez AOP-a bi svaka metoda morala da napiše kod za težinu, održavanje je veoma teško.

Sa AOP-om, treba samo da napišemo jednu aspect klasu, definišemo tačke presecanja i obaveštenja, može se zajednički obraditi. Upravljanje transakcijama je isto, dodaje se @Transactional anotacija i to je to.
Pored toga, Spring integracija raznih enterprise funkcija je posebno dobra. Na primer pristup bazi podataka, bez obzira da li koristimo JDBC, MyBatis-Plus ili Hibernate, Spring može dobro da integriše. Redovi poruka, keš, sigurnosna autentifikacija itd., Spring ima odgovarajuće module za podršku.

Pored toga, Spring konfiguracija je veoma fleksibilna, podržava i XML konfiguraciju i anotacijsku konfiguraciju, sada uglavnom koristimo anotacije, pisanje je jednostavnije. Pojavom Spring Boot-a, postalo je pogodnije, konvencija je veća od konfiguracije, mnoge stvari su spremne za upotrebu.
Kaži jednostavno šta je AOP i IoC?
AOP Aspect-Oriented Programming, jednostavno rečeno, izvlači neke opšte funkcionalnosti iz poslovnog koda i zajednički ih obrađuje. Na primer, u tehničkom stiluanotacija @MdcDot služi da radi sa AOP-om i dodaje MDC informacije u logove, olakšavajući praćenje logova.

IoC Inversion of Control je dizajn ideja, njena glavna uloga je da preda kreiranje objekata i pozive između objekata Spring kontejneru za upravljanje. Na primer, u tehničkom stilu projektu, anotacija @PostConstruct pokazuje da Spring kontejner automatski poziva ovu metodu nakon završetka inicijalizacije Beana, ne moramo ručno da pozivamo init metodu.

Si gledao Spring izvorni kod?
Gledao sam nešto, uglavnom s problemima, na primer kada naiđem na neke teškoće ili želim da dublje razumem neku funkcionalnost.
Fokusirao sam se na proces inicijalizacije IoC kontejnera, posebno ApplicationContext start proces. Od refresh() metode, uključujući definiciju i učitavanje Beana, pripremu Bean fabrike, instanciranje i inicijalizaciju Beana, ove ključne korake.

Čitajući izvorni kod, primetio sam da Spring koristi mnoge dizajn patern, na primer fabrični patern, singleton patern, patern metoda šablona itd., što mi je dalo inspiraciju za pisanje koda.
Pored toga, životni ciklus Spring Beana, od kreiranja BeanDefinition do instanciranja, ubacivanja atributa, inicijalizacije callback, do konačnog uništenja, ceo proces je prilično komplikovan. Nakon čitanja izvornog koda, sam jasnije razumeo vreme izvršavanja anotacija @PostConstruct, @PreDestroy.
Ali iskreno, Spring izvorni kod je stvarno težak za žvakanje, uključuje prevše koncepata i tehničkih tačaka. Obično kombinujem neke tehničke blogove i Claude da čitam, tako mi je razumevanje relativno lakše.
PS: O PDF verziji ovog priručnika, trenutno samo korisnici planete mogu da je dobiju, kasnije ćemo razmisliti da je otvorimo za sve.

- Vodič za Java intervju (plaćeno)sadrži JD učesnika 5 Java pozadinski tehnički prvi intervju originalno pitanje: IoC i AOP
memo: 15. juna 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja sa masterom sa Sun Yat-sen univerziteta, fakultetske nagrade su gotovo maksimalne, veoma odličan, nadam se da mogu da pomognem još prijatelja iz planete, da im pomognu da dobiju bolje ponude.

2.Koje module Spring ima?
Reći ću prema učestalosti kojom se susrećem u svakodnevnom radu/učenju.
Prvo je Spring Core modul, osnova celog Spring okvira, uključuje IoC kontejner i ubacivanje zavisnosti. Pored toga, Spring Beans modul, zadužen za konfiguraciju i upravljanje Bean-om. Ova dva modula su osnova za sve ostale module, bez obzira koju Spring funkcionalnost koristimo, koristimo ih.

Zatim je Spring Context modul, na osnovu Core-a nudi više enterprise funkcionalnosti, na primer internacionalizaciju, propagaciju događaja, učitavanje resursa itd. ApplicationContext je u ovom modulu.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// Spring Boot će automatski kreirati ApplicationContext
ApplicationContext context = SpringApplication.run(Application.class, args);
}
}Spring AOP modul nudi podršku za programiranje orijentisano na aspekte, mi koristimo @Transactional, prilagođene aspekte, sve je bazirano na ovom modulu.
Za web razvoj, Spring Web modul nudi osnovne web funkcionalnosti, Spring WebMVC je naš česti MVC okvir, za obradu HTTP zahteva i odgovora. Sada postoji i Spring WebFlux, podržava reaktivno programiranje.
Na primer, u tehničkom stilu projektu, GlobalExceptionHandler klasa koristi @RestControllerAdvice da realizuje zajedničko rukovanje izuzecima.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = ForumAdviceException.class)
public ResVo<String> handleForumAdviceException(ForumAdviceException e) {
return ResVo.fail(e.getStatus());
}
}Za pristup podacima, Spring JDBC pojednostavljuje korišćenje JDBC-a, u tehničkom stilu projektu, mi koristimo JdbcTemplate da proverimo da li tabela postoji, izvršimo inicijalnu skriptu baze podataka.

Spring ORM nudi podršku za integraciju ORM okvira kao MyBatis-Plus. U tehničkom stilu projektu, mi koristimo @TableName, @TableField itd. anotacije za mapiranje objektnih relacija, kroz nasleđivanje BaseMapper da bismo dobili opšte CRUD mogućnosti.

Spring Test modul nudi podršku za testiranje, veoma pogodno za unit testove i integracione testove. Često koristimo @SpringBootTest itd. anotacije kada pišemo testove. Na primer, u tehničkom stilu projektu, mi koristimo @SpringBootTest anotaciju da učitamo Spring kontekst, radimo integracione testove.
@Slf4j
@SpringBootTest(classes = QuickForumApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class BasicTest {
}Ima i nekoliko drugih modula, na primer Spring Security zadužen za sigurnosnu autentifikaciju, Spring Batch za batch procese itd.
Sada uglavnom koristimo Spring Boot za razvoj, on integriše sve ove module, lakše se koristi.

memo: 16. juna 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja sa masterom sa Dalian Maritime Univerziteta, osnovne studije na Henan Univerzitetu za tehnologiju, u njegovim nagradama se pominju odlični postdiplomci, stipendije, engleski CET-4 i CET-6, nadam se da će studenti koji to vide da pokušaju da dobiju te nagrade, da ne daju te nagrade drugima, ili da uopšte ne znaju, ili da im se ne isplati da učestvuju, tada će ova sekcija na životopisu biti prilično blijeda.

3.Koje često korišćene anotacije Spring ima?
Spring anotacija ima dosta, ja ću ih podeliti po različitim funkcionalnostima i reći za one koje se najviše koriste.
Prvo su anotacije za upravljanje Bean-ovima. @Component je najosnovnija, za identifikaciju klase kao Spring komponente. @Service, @Repository, @Controller su specijalizovane verzije @Component-a, redom za sloj servisa, sloj pristupa podacima i kontroler sloj.

Za ubacivanje zavisnosti, @Autowired se najviše koristi, može se staviti na polje, setter metodu ili konstruktor. @Qualifier se koristi kada ima više istovrsnih Bean-ova da specificira koji se ubacuje. @Resource i @Autowired imaju sličnu funkcionalnost, ali @Resource ubacuje po imenu.

Anotacije za konfiguraciju su takođe česte. @Configuration označava konfiguracijsku klasu, @Bean se koristi za definisanje Beana, @Value za ubacivanje vrednosti atributa iz konfiguracijske datoteke. Informacije o konekciji baze podataka u našem projektu, Redis konfiguracija itd. sve koriste @Value za ubacivanje. @PropertySource se koristi za specificiranje lokacije konfiguracijske datoteke.

Web razvojne anotacije su još brojnije. @RestController je ekvivalent @Controller + @ResponseBody, za RESTful interfejse.

@RequestMapping i njene varijante @GetMapping, @PostMapping, @PutMapping, @DeleteMapping se koriste za mapiranje HTTP zahteva. @PathVariable dobija parametre putanje, @RequestParam dobija parametre zahteva, @RequestBody prima JSON podatke.
AOP anotacije, @Aspect definisanje aspecta, @Pointcut definisanje tačke presecanja, @Before, @After, @Around definisanje tipova obaveštenja.

Ali mi najviše koristimo @Transactional, uglavnom metode servisnog sloja koje treba da garantuju atomičnost transakcije dodaju ovu anotaciju.
Za životni ciklus, @PostConstruct se izvršava nakon inicijalizacije Beana, @PreDestroy pre uništenja Beana. Pri testiranju @SpringBootTest se takođe često koristi.

Ima i nekoliko Spring Boot specifičnih anotacija, na primer @SpringBootApplication ova startna klasna anotacija, @ConditionalOnProperty za uslovno montiranje, @EnableAutoConfiguration za uključivanje automatske konfiguracije itd.

- Vodič za Java intervju (plaćeno)sadržai WeBank učesnik 1 Java pozadinski prvi intervju originalno pitanje: reci Spring česte anotacije?
memo: 17. juna 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja sa fakultetskih osnovnih studija, njegove nagrade su OK, stav je takođe veoma dobar, ranije je fakultetski prijatelj dobio Didi SP ponudu, nadam se da će ovaj prijatelj takođe postati novi uzor u planeti.

4.🌟Kojim dizajn paternima se služi Spring?
Spring okvir zaista koristi mnoge dizajn patern, ja ću reći za nekoliko koje mogu da primetim u svakodnevnom radu.
Prvo je fabrični patern, u Spring-u se veoma koristi. BeanFactory je tipična fabrika, zadužena za kreiranje i upravljanje svim Bean objektima. ApplicationContext koji mi koristimo je takođe implementacija BeanFactory-e. Kada preko @Autowired dobijamo Bean, na nivou ispod se koristi fabrični patern za kreiranje i dobijanje objekata.

Singleton patern je takođe podrazumevano ponašanje Spring-a. Podrazumevano, Beanovi u Spring kontejneru su singletoni, samo jedna instanca u celoj aplikaciji. Tako se štedi memorija, poboljšava performanse. Naravno, možemo promeniti scope Beana preko @Scope anotacije, na primer postaviti na prototype znači da se svaki put kada uzimamo kreira nova instanca.

Proksi patern se posebno mnogo koristi u AOP-u. Spring AOP je baziran na dinamičkom proksiranju, za klase koje implementiraju interfejse koristi JDK dinamički proksi, za klase bez implementacije interfejsa koristi CGLIB proksi. Na primer kada koristimo @Transactional anotaciju, Spring će kreirati proksi objekat za našu klasu, pre i posle izvršenja metode dodati logiku upravljanja transakcijama.
Patern metoda šablona je takođe čest u Spring-u, na primer JdbcTemplate. On definisuje osnovni proces operacije baze podataka: dobavljanje konekcije, izvršavanje SQL-a, obradu rezultata, zatvaranje konekcije, ali konkretne SQL izjave i logiku obrade rezultata implementiramo mi.

Obzerverski patern se ogleda u Spring mehanizmu događaja. Možemo da realizujemo objavljivanje i praćenje događaja kroz ApplicationEvent i ApplicationListener. Na primer nakon uspešne registracije korisnika, možemo objaviti događaj registracije korisnika, zatim ima više slušalaca koji obrađuju sledeću poslovnu logiku, na primer slanje emaila, logging itd.

Primena ovih dizajn paterna čini Spring okvir fleksibilnim i moćnim, i učilo me mnogo klasičnih dizajn ideja pri stvarnom razvoju.
Kako Spring realizuje singleton patern?
Tradicionalni singleton patern je unutrašnja kontrola klase koja može kreirati samo jednu instancu, na primer privatni konstruktor plus static getInstance() način. Ali Spring singleton je na nivou kontejnera, isti Bean u celom Spring kontejneru će imati samo jednu instancu.
Konkretan mehanizam realizacije je ovakav: Spring pri startu učitava sve definicije Bean-a, zatim u klasi DefaultSingletonBeanRegistry održava singletonObjects ovaj ConcurrentHashMap, ovaj Map se koristi za čuvanje singleton Bean-ova. ključ je ime Beana, vrednost je instanca Bean-a.

Kada prvi put uzimamo neki Bean, Spring će prvo proveriti da li postoji ovaj Bean u singletonObjects Map-u, ako ne postoji kreira novu instancu, zatim stavi u Map. Kasnije kada ponovo uzimamo isti Bean, direktno ga uzima iz Map-a, tako se garantuje singleton.

Postoji još jedan detalj, Spring za rešavanje problema kružnih zavisnosti koristi trostruki keš. Pored singletonObjects ovog keša prvog nivoa, postoji earlySingletonObjects keš drugog nivoa i singletonFactories keš trećeg nivoa. Tako čak i kada ima kružnih zavisnosti, Spring može ispravno da obradi.
I Spring singleton je thread-safe, jer koristi ConcurrentHashMap, nema problema pri multi-thread pristupu.
- Vodič za Java intervju (plaćeno)sadržai Ctrip učesnik 10 Java letnja praksa prvi intervju originalno pitanje: dizajn patern IoC Spring-a, dizajn patern AOP Spring-a
- Vodič za Java intervju (plaćeno)sadržai zbirka malih kompanija učesnik 1 Java pozadinski intervju originalno pitanje: dizajn paterni koje Spring okvir koristi?
- Vodič za Java intervju (plaćeno)sadržai učesnik 1 Beike pozadinski tehnički prvi intervju originalno pitanje: kojim dizajn paternima se služi Spring?
- Vodič za Java intervju (plaćeno)sadržai Kuaishou učesnik 4 prvi intervju originalno pitanje: koje dizajn patern Spring koristi, daj primer jednim paternom? Kako Spring realizuje singleton patern?
memo: 20. juna 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja osnovne studije Chongqing Univerziteta za poštu i telekomunikacije, master na Univerzitetu za nauku i tehnologiju u Kini, u međuvremenu je imao iskustva sa istraživačkim projektima Univerziteta Tsinghua, gotovo maksimalno stežu diplomu, nadam se da planeta može pomoći studentima više fakulteta, bilo da rade ili uče, nadam se da svi dobiju bolje ponude.

5.Znaš li razliku između Spring kontejnera i Web kontejnera? (dopuna)
- jula 2024. dodato
Prvo iz koncepcije, Spring kontejner je IoC kontejner, uglavnom zadužen za upravljanje životnim ciklusom Java objekata i zavisnostima. A Web kontejner, na primer Tomcat, Jetty itd., koristi se za pokretanje web aplikacija, zadužen za obradu HTTP zahteva i odgovora, upravljanje životnim ciklusom Servlet-a.
/**
* SpringUtil.java
* Koristi se za dobavljanje Bean-a iz Spring kontejnera, izvorni kod tehničkog stila: https://github.com/itwanger/paicoding
*/
@Component
public class SpringUtil implements ApplicationContextAware {
private volatile static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringUtil.context = applicationContext;
}
public static <T> T getBean(Class<T> bean) {
return context.getBean(bean);
}
}Sa aspekta funkcionalnosti, Spring kontejner se fokusira na upravljanje objektima poslovne logike, naše Service, Dao, Controller Bean-ove sve Spring kontejner kreira i upravlja. A Web kontejner uglavnom obrađuje mrežnu komunikaciju, na primer prima HTTP zahteve, parsira parametre zahteva, poziva odgovarajući Servlet, zatim vraća odgovor klijentu.

U stvarnom projektu, ova dva kontejnera se nadopunju. Naš web projekat se realizuje na Tomcat-u, Tomcat će primiti HTTP zahtev, zatim proslediti zahtev DispatcherServlet-u za obradu, a DispatcherServlet će tražiti odgovarajući Controller iz Spring kontejnera da obradi poslovnu logiku.
/**
* GlobalViewInterceptor.java
* Koristi se za globalni intercepciju, izvorni kod tehničkog stila: https://github.com/itwanger/paicoding
*/
@Component
public class GlobalViewInterceptor implements HandlerInterceptor {
@Autowired
private GlobalInitService globalInitService;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// Web kontejner HTTP zahteva + Spring kontejner poslovni servis
}
}Postoji još jedna važna razlika u životnom ciklusu. Životni ciklus web kontejnera je vezan za realizaciju i uklanjanje web aplikacije, a životni ciklus Spring kontejnera se inicijalizuje pri pokretanju web aplikacije, uništava se pri gašenju aplikacije.
Sada koristimo Spring Boot, Spring Boot ugrađuje Tomcat, integriše web kontejner i Spring kontejner, treba samo da pokrenemo jedan jar fajl.
@SpringBootApplication
public class QuickForumApplication {
public static void main(String[] args) {
SpringApplication.run(QuickForumApplication.class, args);
}
}
- Vodič za Java intervju (plaćeno)sadržai Qunar učesnik 1 tehnički drugi intervju originalno pitanje: razlika između Spring kontejnera, web kontejnera, Spring MVC kontejnera
memo: 27. juna 2025. izmenjeno do ovde, danas sam video da je prijatelj objavio pitanje za izbor ponude, jedno je Hangzhou "šest zmajeva" grupna nuklearna tehnologija, lično mislim da je veoma vredno otići, konačno konačno je jednorog kompanija u Hangzhou-u, plata i beneficija su dobri.

6.Kako razumeš Bean?
Po mom mišljenju, Bean je u suštini Java objekat koji upravlja Spring kontejner, ali ima veliku razliku u odnosu na običan Java objekat. Običan Java objekat mi kreiramo preko new ključne reči. A Bean se preda Spring kontejneru za upravljanje, od kreiranja do uništenja sve je odgovornost kontejnera.

Sa aspekta stvarne upotrebe, naši Service, Dao, Controller u projektu su svi Bean-ovi. Na primer UserService je označen sa @Service anotacijom, postaje Bean, Spring će automatski kreirati njegovu instancu, upravljati njegovim zavisnostima, kada drugim mestima treba UserService, Spring će ubaciti ovu instancu.

Ovaj način ubacivanja zavisnosti čini odnos između objekata labavo spojenim.
Spring nudi više načina konfiguracije Beana, na bazi anotacija je najčešći.

Na bazi XML konfiguracije se u Spring Boot projektu gotovo ne koristi. Način Java konfiguracijske klase može rešiti neke komplikovane scenarije, na primer master-slave baza podataka, možemo koristiti @Primary anotaciju da označimo glavni izvor podataka, @Qualifier da specificiramo rezervni izvor podataka.
@Configuration
public class AppConfig {
@Bean
@Primary // Glavni kandidat
public DataSource primaryDataSource() {
return new HikariDataSource();
}
@Bean
@Qualifier("secondary")
public DataSource secondaryDataSource() {
return new BasicDataSource();
}
}Pri korišćenju, kada direktno koristimo @Autowired anotaciju da ubacimo DataSource, Spring podrazumevano koristi HikariDataSource; kada dodamo @Qualifier("secondary") anotaciju, Spring će ubaciti BasicDataSource.
@Autowired
private DataSource dataSource; // Ubaciće primaryDataSource (zbog @Primary)
@Autowired
@Qualifier("secondary")
private DataSource secondaryDataSource;Koja je razlika između @Component i @Bean?
Prvo iz upotrebe, @Component se stavlja na klasu, a @Bean se stavlja na metodu. @Component kaže Spring-u ova klasa je komponenta, registruj je kao Bean, a @Bean kaže Spring-u registriraj objekat koji vraća ova metoda kao Bean.
@Component // Spring automatski kreira UserService instancu
public class UserService {
@Autowired
private UserDao userDao;
}
@Configuration
public class AppConfig {
@Bean // Mi ručno kreiramo DataSource instancu
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("root");
ds.setPassword("123456");
return ds; // Vraćamo za Spring upravljanje
}
}Sa aspekta kontrole, @Component kreira i upravlja Spring automatski.

A @Bean kreiramo mi ručno, zatim predajemo Spring-u za upravljanje, mi imamo potpunu kontrolu nad procesom kreiranja objekta.

- Vodič za Java intervju (plaćeno)sadržai JD učesnik 9 intervju originalno pitanje: kako razumeš Spring bean, razlika između @Component i @Bean
memo: 28. juna 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja mastera sa Hangdian fakulteta. Ovde želim da kažem jednu tačku, računarski fakultet Hangdian je veoma jak, mada je samo jedan fakultet koji nije 211/985, ako dobro napišete iskustvo projekta i profesionalne veštine, dobijanje top ponude velikih kompanija je apsolutno bez problema.

7.🌟Možeš li reći životni ciklus Bean-a?
Preporučljivo čitanje: Sanfen'e: životni ciklus Spring Bean-a, kao život čoveka
Dobro.
Životni ciklus Bean-a može se podeliti na 5 glavnih faza, ja ću reći po stvarnom redosledu izvršenja.

Prva faza je instanciranje. Spring kontejner će na osnovu BeanDefinition, preko refleksije pozvati konstruktor Bean-a da kreira instancu objekta. Ako ima više konstruktora, Spring će prema pravilima ubacivanja zavisnosti izabrati odgovarajući konstruktor.

Druga faza je dodeljivanje atributa. Ova faza Spring će dodeliti vrednost atributima Bean-a, uključujući zavisne objekte ubacene preko @Autowired, @Resource itd. anotacija, i konfiguracijske vrednosti ubacene preko @Value.

Treća faza je inicijalizacija. Ova faza će se izvršiti redom:
- Metoda označena sa
@PostConstruct - Metoda afterPropertiesSet interfejsa InitializingBean
- Inicijalizaciona metoda specificirana preko initMethod od
@Bean

U projektu često koristim @PostConstruct da radim neke inicijalizacije, na exemple prethodno učitavanje keša, DB konfiguracija itd.
// Inicijalizacija keša u CategoryServiceImpl
@PostConstruct
public void init() {
categoryCaches = CacheBuilder.newBuilder().maximumSize(300).build(new CacheLoader<Long, CategoryDTO>() {
@Override
public CategoryDTO load(@NotNull Long categoryId) throws Exception {
CategoryDO category = categoryDao.getById(categoryId);
// ...
}
});
}
// Inicijalizacija konfiguracije u DynamicConfigContainer
@PostConstruct
public void init() {
cache = Maps.newHashMap();
bindBeansFromLocalCache("dbConfig", cache);
}Nakon inicijalizacije, Spring će pozvati sve registrovane BeanPostProcessor metode post-obrade. Ova faza se često koristi za kreiranje proksi objekata, na primer AOP proksi.
Peta faza je korišćenje Bean-a. Na primer naš Controller poziva Service, Service poziva DAO.
// Primer korišćenja u UserController
@Autowired
private UserService userService;
@GetMapping("/users/{id}")
public UserDTO getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
// Primer korišćenja u UserService
@Autowired
private UserDao userDao;
public UserDTO getUserById(Long id) {
return userDao.getById(id);
}
// Primer korišćenja u UserDao
@Autowired
private JdbcTemplate jdbcTemplate;
public UserDTO getById(Long id) {
String sql = "SELECT * FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper());
}Konačno je faza uništenja. Kada se kontejner gasi ili Bean uklanja, izvršiće se redom:
- Metoda označena sa
@PreDestroy - Metoda destroy interfejsa DisposableBean
- Metoda uništenja specificirana preko destroyMethod od
@Bean

Koju ulogu imaju interfejsi tipa Aware?
Aware interfejs u Spring-u je zanimljiv dizajn, njihova uloga je da Bean može da oseti neke interne komponente Spring kontejnera.
Sa aspekta dizajnerske filozofije, Aware interfejs realizuje mehanizam "callback". U normalnim okolnostima, Bean ne bi trebao direktno da zavisi od Spring kontejnera, tako da se može održati nezavisnost koda. Ali ponekad, Bean zaista treba da dobije neke informacije ili komponente kontejnera, Aware interfejs pruža ovu mogućnost.
Najčešći Aware interfejs koji koristim je ApplicationContextAware, omogućava Bean-u da dobije ApplicationContext kontejner sam.

U tehničkom stilu projektu, ja sam implementiranjem ApplicationContextAware i EnvironmentAware interfejsa enkapsulirao SpringUtil alatnu klasu, preko getBean i getProperty metoda da dobijem Bean i konfiguracijske atribute.
// Statička metoda za dobavljanje Bean-a, pogodno za korišćenje u klasama koje Spring ne upravlja
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
// Dobavljanje konfiguracijskog atributa
public static String getProperty(String key) {
return environment.getProperty(key);
}Ako se konfiguriše init-method i destroy-method, kada će ih Spring pozvati?
Inicijalizaciona metoda specificirana initMethod će se pozvati u fazi inicijalizacije Bean-a, konkretan redosled izvršenja je:
- Prvo se izvršava metoda označena sa
@PostConstruct - Zatim metoda
afterPropertiesSet()interfejsa InitializingBean - Konačno metoda specificirana initMethod
To jest, initMethod se izvršava nakon svih ostalih inicijalizacionih metoda.
@Component
public class MyService {
@Autowired
private UserDao userDao;
@PostConstruct
public void postConstruct() {
System.out.println("1. @PostConstruct se izvršava");
}
public void customInit() { // Specificirano preko initMethod od @Bean
System.out.println("3. init-method se izvršava");
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "customInit")
public MyService myService() {
return new MyService();
}
}destroyMethod će se pozvati u fazi uništenja Bean-a.
@Component
public class MyService {
@PreDestroy
public void preDestroy() {
System.out.println("1. @PreDestroy se izvršava");
}
public void customDestroy() { // Specificirano preko destroyMethod od @Bean
System.out.println("3. destroy-method se izvršava");
}
}Ali u stvarnom razvoju, obično je @PostConstruct i @PreDestroy dovoljno, jednostavniji su.
- Vodič za Java intervju (plaćeno)sadržai Xiaomi 25. generacija redovna praksa prvi intervju originalno pitanje: reci životni ciklus Bean-a
- Vodič za Java intervju (plaćeno)sadržai Baidu učesnik 1 Wenxin Yiyan 25 praksa Java pozadinski intervju originalno pitanje: životni ciklus Bean-a u Spring-u
- Vodič za Java intervju (plaćeno)sadržai 8 pozadinski razvoj jesenja regrutacija prvi intervju originalno pitanje: reci životni ciklus Spring Bean-a
- Vodič za Java intervju (plaćeno)sadržai učesnik 1 Beike pozadinski tehnički prvi intervju originalno pitanje: životni ciklus Bean-a
- Vodič za Java intervju (plaćeno)sadržai Kuaishou učesnik 4 prvi intervju originalno pitanje: predstavi životni ciklus Bean-a? Koju ulogu imaju interfejsi tipa Aware? Ako se konfiguriše init-method i destroy-method, kada će ih Spring pozvati?
memo: 30. juna 2025. izmenjeno do ovode. Juče je čitalac poslao poruku da ima tri ponude za biranje, doktorat na USTC, CNOOC, COMAC Peking istraživački institut, pitao me kako da bira? Iskreno, ova tri su sve vrlo kvalitetna izbora, moj lični predlog je da se prvo razmotri doktorat na USTC, konačno konačno je vrhunski univerzitet u Kini, nakon doktorskih studija može se predavati na fakultetu, više odgovara uslovima njegove porodice, naravno, vrlo dobro znam, pritisak doktorske proizvodnje je vrlo velik.

8.Koje oblasti delovanja Bean-a postoje?
Oblast delovanja Bean-a određuje životni ciklus i strategiju kreiranja instance Bean-a, singleton je podrazumevana oblast. U celom Spring kontejneru će postojati samo jedna instanca Bean-a. Bez obzira na koliko mesta ubacujemo ovaj Bean, dobijamo isti objekat.
@Component // Podrazumevano je singleton
public class UserService {
// U celoj aplikaciji postoji samo jedna UserService instanca
}Životni ciklus je isti kao Spring kontejner, kreira se pri pokretanju kontejnera, uništava se pri gašenju kontejnera.
U stvarnom razvoju, Service, Dao itd. poslovne komponente su uglavnom singletoni, jer singleton štedi memoriju i poboljšava performanse.
Kada se scope postavi na prototype, svaki put kada se uzima Bean iz kontejnera kreira se nova instanca.
@Component
@Scope("prototype")
public class OrderProcessor {
// Svako ubacivanje ili uzimanje je nova instanca
}Kada treba da se obrade neki Bean-ovi sa stanjem koristi se prototype, na primer svaki procesor narudžbine treba da održava različite informacije o stanju.
Treba obratiti pažnju, kada se ubacuje prototype Bean u singleton Bean treba biti oprezan, jer se singleton Bean kreira samo jednom, prototype Bean će se ubaciti samo jednom. Ovde se može koristiti @Lookup anotacija ili ApplicationContext da se dinamički dobija.
@Component
public class SingletonService {
// Pogrešan način, prototypeBean će se ubaciti samo jednom
@Autowired
private PrototypeBean prototypeBean;
// Ispravan način, svaki put kad se poziva dobija se nova instanca
@Lookup
public PrototypeBean getPrototypeBean() {
return null; // Spring će prebrisati ovu metodu
}
}Pored singletona i prototipa, Spring podržava i druge oblasti, na primer request, session, application i websocket.

Ako je oblast request, to znači da u web aplikaciji svaki HTTP zahtev kreira novu instancu Bean-a, nakon završetka zahteva Bean se uništava.
@Component
@Scope("request")
public class RequestContext {
// Svaki HTTP zahtev ima svoju instancu
}Ako je oblast session, to znači da u web aplikaciji svaka HTTP sesija kreira novu instancu Bean-a, nakon završetka sesije Bean se uništava.
@Component
@Scope("session")
public class UserSession {
// Svaka korisnička sesija ima svoju instancu
}Tipična scena upotrebe je korpa za kupovinu, stanje prijave korisnika itd. informacije koje treba održavati tokom cele sesije.
application oblast znači da u celoj aplikaciji postoji samo jedna instanca Bean-a, slično kao singleton, ali njen životni ciklus je vezan za ServletContext.
@Component
@Scope("application")
public class AppConfig {
// U celoj aplikaciji postoji samo jedna instanca
}websocket oblast znači da u WebSocket sesiji svaka veza ima svoju instancu Bean-a. Kreira se pri uspostavljanju WebSocket veze, uništava se pri gašenju veze.
@Component
@Scope("websocket")
public class WebSocketHandler {
// Svaka WebSocket veza ima svoju instancu
}
- Vodič za Java intervju (plaćeno)sadržai učesnik 1 Beike pozadinski tehnički prvi intervju originalno pitanje: da li je Bean singleton ili višestruki, kako se konkretno menja
memo: 3. jula 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja mastera sa Univerziteta u Zhengzhou-u, osnovne studije na Hebei pedagoškom univerzitetu, celokupno iskustvo na fakultetu je vrlo izvrsno, stipendije, radovi u časopisima su skoro maksimalni. Toliko mnogo odličnih prijatelja iz planete je izabralo da dođe ovde, takođe je još jedno priznanje i potvrda planete, sigurno ću nastaviti da radim, da pružim više kvalitetnog sadržaja i usluga.

9.Da li Spring singleton Bean ima problem thread-safe?
Prvo treba jasno reći. Spring kontejner garantuje proces kreiranja Bean-a je thread-safe, to jest neće se desiti da više niti istovremeno kreira isti singleton Bean. Ali nakon završenog kreiranja Bean-a, Spring ne upravlja procesom korišćenja.
Drugim rečima, ako je interno stanje singleton Bean-a promenljivo, u multi-thread okruženju može se desiti problem thread-safe.

Na primer u tehničkom stilu projektu, postoji Bean za filtriranje osetljivih reči, mi treba da koristimo volatile ključnu reč da garantiramo vidljivost u multi-thread okruženju.
@Service
public class SensitiveService {
private volatile SensitiveWordBs sensitiveWordBs; // Koristimo volatile za vidljivost
@PostConstruct
public void refresh() {
// Re-inicijalizacija sensitiveWordBs
}
}Ako Bean nema promenljivih članova, ili su svi članovi nepromenljivi, final modifikovani, onda ne postoji problem thread-safe.
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserDao userDao;
@Autowired
private CountService countService;
// Samo zavisne ubacene bez stanja
}
@Service
public class ConfigService {
private final String appName; // final modifikovan, nepromenljiv
public ConfigService(@Value("${app.name}") String appName) {
this.appName = appName;
}
}Kako rešiti problem thread-safe singleton Bean-a?
Prvi, koristiti lokalne promenljive, to jest koristiti bezstate singleton Bean, sva stanja se prenose preko parametara metoda:
@Service
public class UserService {
@Autowired
private UserDao userDao;
// Bezstate metoda, svi podaci se prenose preko parametara
public User processUser(Long userId, String operation) {
User user = userDao.findById(userId);
// Poslovna logika...
return user;
}
}Drugi, kada zaista treba održavati stanja vezana za nit, može se koristiti ThreadLocal za čuvanje stanja. ThreadLocal može garantovati da svaka nit ima svoj kopiju promenljive, ne ometaju se.
@Service
public class UserContextService {
private static final ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
public void setCurrentUser(User user) {
userThreadLocal.set(user);
}
public User getCurrentUser() {
return userThreadLocal.get();
}
public void clear() {
userThreadLocal.remove(); // Sprječava curenje memorije
}
}Treći, ako treba keširati podatke ili brojati, koristiti thread-safe klase iz JUC paketa, na primer AtomicInteger, ConcurrentHashMap, CopyOnWriteArrayList itd.
@Service
public class CacheService {
// Koristimo thread-safe kolekcije
private final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();
private final AtomicLong counter = new AtomicLong(0);
public void put(String key, Object value) {
cache.put(key, value);
counter.incrementAndGet();
}
}Četvrti, za komplikovane operacije stanja, može se koristiti synchronized ili Lock:
@Service
public class CacheService {
private final Map<String, Object> cache = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock();
public void put(String key, Object value) {
lock.lock();
try {
cache.put(key, value);
} finally {
lock.unlock();
}
}
}Peti, ako Bean zaista treba da održava stanje, može se razmotriti da se promeni u prototype oblast, tako da se svaki put pri ubacivanju kreira nova instanca, izbegava se problem više niti dele istu instancu.
@Service
@Scope("prototype") // Svako ubacivanje kreira novu instancu
public class StatefulService {
private String state; // Sada svaka instanca ima nezavisno stanje
public void setState(String state) {
this.state = state;
}
}Ili se koristi request oblast, tako da se svaki HTTP zahtev kreira nova instanca.
@Service
@Scope("request")
public class RequestScopedService {
private String requestData;
// Svaki zahtev ima nezavisnu instancu
}
- Vodič za Java intervju (plaćeno)sadržai Alibaba učesnik 1 Xianyu pozadinski prvi intervju originalno pitanje: problem konkurentnosti Bean-a u spring-u
memo: 4. jula 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja mastera sa Wuhan Univerziteta za tehnologiju. Istinski, vrlo sam povezan sa Wuhan Univerzitetom za tehnologiju, 2023. sam išao u Wuhan, tada sam se lično sreo sa jednim prijateljem sa WUT-a, on je tada potpisao sa Xiaomi, veoma odličan.

10. Zašto IDEA ne preporučuje korišćenje @Autowired anotacije za ubacivanje Bean-a?
Pozadina: kada se koristi @Autowired anotacija za ubacivanje Bean-a, IDEA će prikazati "Field injection is not recommended".

Intervju odgovor:
Ima nekoliko razloga.
Prvi, ubacivanje polja je pogubno za unit testiranje. Ubacivanje polja zahteva upotrebu refleksije ili Spring kontejner da bi se ubacile zavisnosti, testiranje je komplikovanije; a ubacivanje konstruktora može direktno preko konstruktora proslediti Mock objekat, testiranje je jednostavnije.
// Težina testiranja ubacivanja polja
@Test
public void testUserService() {
UserService userService = new UserService();
// Ne može se direktno postaviti userRepository, treba refleksija ili Spring kontejner
// userService.userRepository = Mockito.mock(UserRepository.class);
// Treba ručno postaviti zavisnosti, testiranje je nepogodno
ReflectionTestUtils.setField(userService, "userRepository", Mockito.mock(UserRepository.class));
userService.doSomething();
// ...
}
// Jednostavnost testiranja ubacivanja konstruktora
@Test
public void testUserService() {
UserRepository mockRepository = Mockito.mock(UserRepository.class);
UserService userService = new UserService(mockRepository); // Direktno ubacivanje
}Drugi, ubacivanje polja skriva probleme kružnih zavisnosti, a ubacivanje konstruktora će pri startu projekta proveriti odnos zavisnosti, može ranije otkriti probleme.
Treći, ubacivanje konstruktora može koristiti final polja da garantuje da su zavisnosti inicijalizovane pri kreiranju objekta, izbegava se rizik kasnije izmene.
U tehničkom stilu projektu, mi već koristimo način ubacivanja konstruktora za upravljanje zavisnostima.

Ali ipak, način ubacivanja polja @Autowired u jednostavnim scenarijima se može koristiti, uglavnom zavisi od timskog koding standarda.
Koja je razlika između @Autowired i @Resource anotacije?
Prvo iz izvora, @Autowired je anotacija koju pruža Spring okvir, a @Resource je anotacija koju pruža Java EE standard. Drugim rečima, @Resource dolazi sa JDK-om, a @Autowired je specifičan za Spring.
Iako IDEA ne preporučuje korišćenje @Autowired, za @Resource anotaciju nema nikakvog upozorenja.

Sa aspekta načina ubacivanja, @Autowired podrazumevano po tipu, odnosno byType ubacuje, a @Resource podrazumevano po imenu, odnosno byName ubacuje.
Kada u kontejneru postoji više Bean-ova istog tipa, na primer ako ima dve implementacije klase UserRepository, direktno korišćenje @Autowired za ubacivanje UserRepository će prijaviti grešku, jer Spring kontejner ne zna koju implementaciju da ubaci.
@Component
public class UserRepository21 implements UserRepository2 {}
@Component
public class UserRepository22 implements UserRepository2 {}
@Component
public class UserService2 {
@Autowired
private UserRepository2 userRepository; // Konflikt
}Ovde postoje dva rešenja, prvo je korišćenje @Autowired + @Qualifier da specificira konkretan naziv Bean-a za rešavanje konflikta.
@Component("userRepository21")
public class UserRepository21 implements UserRepository2 {
}
@Component("userRepository22")
public class UserRepository22 implements UserRepository2 {
}
@Autowired
@Qualifier("userRepository22")
private UserRepository2 userRepository22;Drugo je korišćenje @Resource anotacije za ubacivanje po imenu.
@Resource(name = "userRepository21")
private UserRepository2 userRepository21;
- Vodič za Java intervju (plaćeno)sadržai JD učesnik 9 intervju originalno pitanje: pri ubacivanju zavisnosti, direktno Autowired je direktnije, zašto se preporučuje ubacivanje konstruktora
memo: 1. jula 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja mastera sa Univerziteta u Zhengzhou-u, ovo je takođe najbolji univerzitet u našoj provinciji Henan, ali je takođe samo jedan 211, zato se nadam da svi studenti iz Henana mogu da daju sve od sebe, dokažu svoju snagu, da dobiju bolje ponude, daju slavu školi.

11.Znaš li princip realizacije @Autowired?
@Autowired je ključna anotacija Spring za realizaciju ubacivanja zavisnosti, njen princip realizacije se bazira na mehanizmu refleksije i interfejsu BeanPostProcessor.
Ceo proces se deli na dve glavne faze. Prva faza je faza prikupljanja zavisnosti, dešava se nakon instanciranja Bean-a, pre dodele atributa. Autowired Processor će skenirati sva polja, metode i konstruktore Bean-a, pronaći mesta označena sa @Autowired anotacijom, zatim te informacije enkapsulirati u Injection metadat objekat i keširati. Ovaj proces koristi mnogo operacija refleksije, treba analizirati strukturu klase, informacije o anotacijama itd.

Druga faza je faza ubacivanja zavisnosti, Spring će uzeti prethodno keširane Injection metadat objekte, zatim redom obrađuje svaku tačku ubacivanja. Za svako polje ili metodu označenu sa @Autowired, Spring će prema tipu tražiti odgovarajući Bean u kontejneru.
// 1. Pretraga po tipu (byType)
Map<String, Object> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
this.beanFactory, type);
// 2. Ako se pronađu više kandidata, filtriranje po imenu (byName)
String autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
// 3. Razmotri @Primary i @Priority anotacije
// 4. Konačno upoređivanje po imenu polja ili parametraU konkretnom procesu ubacivanja, Spring će koristiti refleksiju za postavljanje vrednosti polja ili pozivanje setter metode. Na primer za ubacivanje polja, pozvaće se Field.set() metoda; za setter ubacivanje, pozvaće se Method.invoke() metoda.
12.Šta je automatsko montiranje?
Esencija automatskog montiranja je da Spring kontejner automatski završi ubacivanje zavisnosti između Bean-ova za nas, ne trebamo ručno da specificiramo svaku zavisnost. Jednostavno rečeno, "ne moramo da govorimo Spring-u kako da ubaci, Spring sam će naći način da pronađe odgovarajući Bean i ubaci".
Radni princip automatskog montiranja je jednostavan, Spring kontejner pri startu automatski skenira sve klase putanje specificirane sa @ComponentScan, zatim prema anotacijama na klasama, na primer @Autowired, @Resource itd., da oceni koje Bean-ove treba automatski montirati.
@Configuration
@ComponentScan("com.github.paicoding.forum.service")
@MapperScan(basePackages = {
"com.github.paicoding.forum.service.article.repository.mapper",
"com.github.paicoding.forum.service.user.repository.mapper"
// ... još putanja paketa
})
public class ServiceAutoConfig {
// Spring automatski skenira sve komponente u navedenim paketima i registruje kao Bean-ove
}Zatim analizira odnos zavisnosti svakog Bean-a, pri kreiranju Bean-a, prema pravilima montiranja automatski pronalazi odgovarajuće zavisne Bean-ove, konačno preko refleksije ubacuje te zavisnosti u ciljni Bean.
Koje vrste automatskog montiranja Spring nudi?
Automatsko montiranje Spring ima nekoliko vrsta, u eri XML konfiguracije, uglavnom postojale četiri vrste: byName, byType, constructor i autodetect.

U eri anotacijskog upravljanja, najviše se koristi @Autowired anotacija, podrazumevano se montira po tipu.
@Service
public class UserService {
@Autowired // Automatsko montiranje po tipu
private UserRepository userRepository;
}Zatim postoji @Resource anotacija, podrazumevano se montira po imenu, ako ne pronađe odgovarajući naziv Bean-a, onda će se montirati po tipu.
Automatsko montiranje Spring Boot-a ima i jedan napredniji mehanizam, preko @EnableAutoConfiguration i raznih @Conditional anotacija za realizaciju, ovo je automatsko montiranje na nivou okvira, automatski će konfigurisati Bean-ove prema klasama u classpath-u i konfiguraciji.

- Vodič za Java intervju (plaćeno)sadržai oppo učesnik 15 tehnički intervju originalno pitanje: princip automatskog montiranja spring-a, princip startovanja, kako da prilagodim logiku u fazi startovanja?
memo: 2. jula 2025. izmenjeno do ovde, danas sam pomagao prijateljima iz planete da izmene životopis, sreo sam prijatelja sa Beihang Univerziteta za aeronautiku i astronautiku, u emailu je rekao: na planeti sam naučio mnogo stvari, trenutno se pripremam za tehnički stili MYDB, nameravam dobro da se pripremim za jesenju regrutaciju, što mogu da pomognem svima zaista me raduje.

13.Šta je kružna zavisnost?
Jednostavno rečeno, dva ili više Bean-ova međusobno zavise, na primer A zavisi od B, B zavisi od A, ili C zavisi od C, to je kružna zavisnost.

14.🌟Kako Spring rešava kružnu zavisnost?
Spring rešava kružnu zavisnost kroz mehanizam trostrukog keša:
- Keš prvog nivoa: čuva potpuno inicijalizovane singleton Bean-ove.
- Keš drugog nivoa: čuva unapred izložene Bean-ove, instancirane, ali ne inicijalizovane.
- Keš trećeg nivoa: čuva Bean fabrike, za generisanje unapred izloženih Bean-ova.

Uzmimo primer kružne zavisnosti između A i B dve klase:

Korak 1: Počinje kreiranje Bean-a A.
- Spring poziva konstruktor A, kreira instancu A. U ovom trenutku objekat A postoji, ali b atribut je još uvek null.
- Stavlja fabriku objekta A u keš trećeg nivoa.
- Počinje ubacivanje atributa A.

Korak 2: A treba da ubaci B, počinje kreiranje Bean-a B.
- Otkriva da treba B, ali B još ne postoji, počinje kreiranje B.
- Poziva konstruktor B, kreira instancu B. U ovom trenutku objekat B postoji, ali a atribut je još uvek null.
- Stavlja fabriku objekta B u keš trećeg nivoa.
- Počinje ubacivanje atributa B.
Korak 3: B treba da ubaci A, dobija A iz keša.
- B treba da ubaci A, prvo traži A u kešu prvog nivoa, nije pronašao.
- Zatim traži A u kešu drugog nivoa, takođe nije pronašao.
- Konačno traži A u kešu trećeg nivoa, pronašao fabriku objekta A.
- Poziva fabriku objekta A i dobija instancu A. U ovom trenutku A je već instanciran, mada još uvek potpuno nije inicijalizovan.
- Premešta A iz keša trećeg nivoa u keš drugog nivoa.
- B dobija referencu na A, završava ubacivanje atributa.

Korak 4: B završava inicijalizaciju.
- B završava ubacivanje atributa, izvršava
@PostConstructitd. inicijalizacionu logiku. - B je potpuno kreiran, uklanja se iz keša trećeg nivoa, stavlja se u keš prvog nivoa.
Korak 5: A završava inicijalizaciju.
- Vraća se na proces kreiranja A, A dobija potpunu instancu B, završava ubacivanje atributa.
- A izvršava inicijalizacionu logiku, kreiranje je završeno.
- A se uklanja iz keša drugog nivoa, stavlja se u keš prvog nivoa.

Da simuliramo ovaj proces kodom, ovako izgleda:
// Simulacija Spring procesa rešavanja
public class CircularDependencyDemo {
// Trostruki keš
Map<String, Object> singletonObjects = new HashMap<>();
Map<String, Object> earlySingletonObjects = new HashMap<>();
Map<String, ObjectFactory> singletonFactories = new HashMap<>();
public Object getBean(String beanName) {
// Prvo dobavi iz keša prvog nivoa
Object bean = singletonObjects.get(beanName);
if (bean != null) return bean;
// Zatim dobavi iz keša drugog nivoa
bean = earlySingletonObjects.get(beanName);
if (bean != null) return bean;
// Konačno dobavi iz keša trećeg nivoa
ObjectFactory factory = singletonFactories.get(beanName);
if (factory != null) {
bean = factory.getObject();
earlySingletonObjects.put(beanName, bean); // Premesti u keš drugog nivoa
singletonFactories.remove(beanName); // Ukloni iz keša trećeg nivoa
}
return bean;
}
}U kojim slučajevima Spring ne može da reši kružnu zavisnost?
Iako Spring može da reši većinu problema kružnih zavisnosti, zaista postoje nekoliko slučajeva koje ne može da obradi, detaljno ću reći.

Prvi, kružna zavisnost konstruktora, u ovom slučaju Spring će direktno baciti BeanCurrentlyInCreationException izuzetak.
@Component
public class A {
private B b;
public A(B b) { // Ubacivanje konstruktora
this.b = b;
}
}
@Component
public class B {
private A a;
public B(A a) { // Ubacivanje konstruktora
this.a = a;
}
}Jer se ubacivanje konstruktora dešava u fazi instanciranja, pri kreiranju A mora prvo postojati B, ali pri kreiranju B mora prvo postojati A, u ovom trenutku oba objekta još nisu kreirana, ne mogu se unapred izložiti u keš.
Drugi, kružna zavisnost oblasti prototype. Bean-ovi oblasti prototype se svaki put kada se uzimaju kreira nova instanca, Spring ne može da kešira te instance, takođe ne može da reši kružnu zavisnost.
----može se ne memorisati na intervjuu, za lakše razumevanje sve počinje----
Da pogledamo jedan primer, prvo PrototypeBeanA:
@Component
@Scope("prototype")
public class PrototypeBeanA {
private final PrototypeBeanB prototypeBeanB;
@Autowired
public PrototypeBeanA(PrototypeBeanB prototypeBeanB) {
this.prototypeBeanB = prototypeBeanB;
}
}Zatim PrototypeBeanB:
@Component
@Scope("prototype")
public class PrototypeBeanB {
private final PrototypeBeanA prototypeBeanA;
@Autowired
public PrototypeBeanB(PrototypeBeanA prototypeBeanA) {
this.prototypeBeanA = prototypeBeanA;
}
}Zatim test:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
// Pokušaj da dobiješ instancu PrototypeBeanA
PrototypeBeanA beanA = ctx.getBean(PrototypeBeanA.class);
};
}
}Rezultat izvršenja:

----kraj mogućnosti ne memorisanja na intervjuu----
- Vodič za Java intervju (plaćeno)sadržai Xiaomi 25. generacija redovna praksa prvi intervju originalno pitanje: kako rešiti kružnu zavisnost?
- Vodič za Java intervju (plaćeno)sadržai Baidu učesnik 1 Wenxin Yiyan 25 praksa Java pozadinski intervju originalno pitanje: kako Spring rešava kružnu zavisnost?
- Vodič za Java intervju (plaćeno)sadržai Dewu učesnik 9 intervju pitanje originalno pitanje: Si gledao Spring izvorni kod? Znaš li trostruki keš Spring-a?
- Vodič za Java intervju (plaćeno)sadržai Alibaba Cloud učesnik 22 iskustvo: problem rešavanja kružne zavisnosti trostrukim kešom spring-a
memo: 5. jula 2025. izmenjeno do ovde. Danas je VIP grupadobila mnogo prijatelja, nehotice smo već na 21 grupi, takođe je velika porodica, nadam se da svi mogu da nađu osećaj pripadnosti ovde, učimo zajedno, napredujemo zajedno.

15. Zašto treba trostruki keš a ne dvostruki?
Spring dizajn trostrukog keša uglavnom je zbog rešavanja AOP proksi problema.
Dajem konkretan primer za objašnjenje. Pretpostavimo da imamo A i B dve klase međusobno zavisne, na nekoj metodi A je označena @Transactional anotacijom, to znači da A konačno treba biti kreiran kao proksi objekat od Spring-a.
@Component
public class A {
@Autowired
private B b;
@Transactional // A treba biti AOP proksi
public void doSomething() {
// Poslovna logika
}
}
@Component
public class B {
@Autowired
private A a;
}Ako postoji samo keš drugog nivoa, pri kreiranju A treba unapred staviti originalni objekat A u keš, zatim B pri kreiranju uzima originalni objekat A iz keša.
// Pretpostavimo da postoji samo keš drugog nivoa
Map<String, Object> singletonObjects = new HashMap<>(); // Potpuni Bean
Map<String, Object> earlySingletonObjects = new HashMap<>(); // Nedovršeni BeanAli problem je što nakon što A završi inicijalizaciju, zbog @Transactional anotacije, Spring će upakovati A kao proksi objekat i staviti u kontejner. Tako se pojavljuje veoma ozbiljan problem: B drži originalni objekat A, a u kontejneru je proksi objekat A, isti Bean ima dve različite instance, ovo sigurno nije ispravno.

Trostruki keš je dizajniran baš za rešavanje ovog problema. U kešu trećeg nivoa se ne čuva instanca Bean-a, nego fabrika objekata, ovo je funkcionalni interfejs.
Kada B treba A, poziva se getObject metoda ove fabrike objekata, u ovoj metodi će se proceniti da li A treba biti proksi. Ako treba, kreira proksi objekat A i vraća B; ako ne treba, vraća originalni objekat A. Tako se garantuje da A koji B dobija i A koji se konačno stavlja u kontejner su isti objekat.
Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
// Logika u Spring izvornom kodu
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// Ključno: ako treba proksi, ovde će se kreirati proksi objekat
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}Jednostavno rečeno, ključna uloga keša trećeg nivoa je odložena odluka. Omogućava Spring-u da tek kad zaista treba Bean odluči da li da vrati originalni objekat ili proksi objekat, tako se izbegava problem neusklađenosti objekata. Bez keša trećeg nivoa, Spring ne bi mogao da podrži AOP u slučaju kružnih zavisnosti, ili bi se pojavio problem da isti Bean ima više instanci, oboje je neprihvatljivo.

Koji bi bio problem ako nedostaje keš drugog nivoa?
Keš drugog nivoa earlySingletonObjects uglavnom čuva referencu ranijih Bean-ova koji su već kreirani kroz fabriku objekata keša trećeg nivoa.

Pretpostavimo da imamo tri Bean-a A, B, C, A zavisi od B i C, B i C oba zavise od A, formiraju kompleksnu kružnu zavisnost. Bez keša drugog nivoa, svaki put kad B ili C trebaju A, treba pozvati getObject metodu fabrike objekata A u kešu trećeg nivoa. To znači da ako A treba biti proksi, proksi objekat može biti kreiran više puta, ovo je očigledno nerazumno.
// Pseudokod bez keša drugog nivoa
public Object getSingleton(String beanName) {
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// Direktno uzimaj iz keša trećeg nivoa
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
return singletonFactory.getObject(); // Svaki put će se kreirati novi proksi objekat!
}
}
return singletonObject;
}Dajem konkretan primer. Na primer A ima @Transactional anotaciju treba biti AOP proksi, B pri inicijalizaciji treba A, pozvaće se jednom fabrika objekata da kreira proksi objekat A. Zatim C pri inicijalizaciji takođe treba A, opet će pozvati fabriku objekata, možda će opet kreirati jedan proksi objekat A. Tako B i C mogu dobiti dva različita proksi objekta A, to krši semantiku singleton Bean-a.
@Service
public class ServiceA { @Autowired
private ServiceB serviceB;
@Transactional // potreban AOP proxy
public void methodA() {
// poslovna logika
}
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA; // dobija proxy objekat A1
@Autowired
private ServiceC serviceC;
}
@Service
public class ServiceC {
@Autowired
private ServiceA serviceA; // možda dobija proxy objekat A2
}Sekundarni keš rešava ovaj problem. Kada se prvi put putem fabrike objekata kreira rana referenca na A, ta se referenca stavi u sekundarni keš, a istovremeno se uklanja fabrika objekata iz tercijarnog keša.
// Prvo dobijanje A
ObjectFactory<A> factory = singletonFactories.get("serviceA");
Object proxyA = factory.getObject(); // kreiranje proxy-ja
earlySingletonObjects.put("serviceA", proxyA); // keširanje proxy-ja
singletonFactories.remove("serviceA");
// Drugo dobijanje A
Object cachedA = earlySingletonObjects.get("serviceA"); // direktno povratak keširanog proxy-ja
// proxyA == cachedA ✓Nakon toga, ako drugi Bean-ovi trebaju A, direktno ga dobijaju iz sekundarnog keša, bez potrebe za pozivanjem fabrike objekata.
- Java vodič za razgovor (plaćeni) uključuje pitanje s prvog intervjuua zaposlenog u Kuaishouu 4: da li ste čuli za cirkularne zavisnosti? Zašto nastaju cirkularne zavisnosti? Koje su razlike u sadržaju tri keša? Kako rešiti cirkularne zavisnosti? Koji bi problemi nastali ako ne bi postojao sekundarni keš?
IoC
16.🌟Kažite šta je IoC?
Preporučujem čitanje: IoC čišćenje
IoC je Inversion of Control, odnosno inverzija kontrole. Ovde “kontrola” podrazumeva kontrolu nad kreiranjem objekata i upravljanjem relacijama zavisnosti.

Ranije kada smo pisali kod, ako klasa A treba da koristi klasu B, mi bismo u klasi A direktno kreirali novi objekat B, tako da klasa A kontroliše kreiranje objekta klase B.
// Tradicionalni način: objekat aktivno kreira zavisnosti
public class UserService {
private UserDao userDao;
public UserService() {
// Aktivno kreiranje objekta zavisnosti
this.userDao = new UserDaoImpl();
}
}Sa IoC-om, ova kontrola se “invertuje”, više ne klasa A kontroliše kreiranje objekta B, već se to predaje eksternom kontejneru za upravljanje.
/**
* Korišćenje Spring IoC kontejnera za upravljanje kreiranjem i injektiranjem UserDao
* Tehnički izvorni kod: https://github.com/itwanger/paicoding
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
// Nije potrebno aktivno kreirati UserDao, to Spring kontejner injektira
public BaseUserInfoDTO getAndUpdateUserIpInfoBySessionId(String session, String clientIp) {
// Direktno korišćenje injektiranog userDao
return userDao.getBySessionId(session);
}
}----Ovaj deo nije neophodno pamćenje za intervju start----
Pre IoC-a:
Trebam mi devojka, baš sam na ulici iznenada video jednu devojku, vrlo lepu, pa sam joj sam aktivno pristupio, tražio njen WeChat ID, tražio priliku da ćebam sa njom, a onda sam je pozivao na večeru, istraživao njen hobbi, vrednosni sistem...
Sa IoC-om:
Trebam mi devojka, pa sam otišao u agenciju za venčavanja, rekao agenciji za venčavanja da trebam devojku koja liči na Zha Luzia, koja igra Dota2, pa je agencija za venčavanje počela da traži u svojoj bazi talenata, ako ne pronađe, direktno kaže da nema, ako pronađe, direktno mi je predstavlja.
Agencija za venčavanja je jednaka IoC kontejneru, ja sam objekat, devojka koju trebam je drugi objekat, ne brinem se odakle devojka dolazi, samo trebam reći agenciji za venčavanje kakvu devojku trebam, i agencija za venčavanje mi pomaže da je pronađem.

----Ovaj deo nije neophodno pamćenje za intervju end----
Da li znate razliku između DI i IoC?
Ideja IoC-a je prenos kontrole nad kreiranjem objekata i relacijama zavisnosti iz poslovnog koda na Spring kontejner. Ovo je prilično apstraktan koncept koji nam govori kako trebamo da dizajniramo arhitekturu sistema.

A DI, odnosno Dependency Injection, predstavlja konkretan tehnički metod za realizaciju IoC ideje. U Spring-u, kada koristimo @Autowired anotaciju, koristimo metodu injektiranja polja DI-ja.
@Service
public class ArticleReadServiceImpl implements ArticleReadService {
@Autowired
private ArticleDao articleDao; // injektiranje polja
@Autowired
private UserDao userDao;
}Sa aspekta implementacije, pored injektiranja polja, DI ima i metode injektiranja konstruktora i Setter metode. Prilikom rada na Tehnički projektu, probao sam metodu injektiranja konstruktora.

Naravno, DI nije jedini način realizacije IoC-a, postoji i Service Locator pattern, koji može dobiti Bean-ove iz Spring kontejnera implementacijom ApplicationContextAware interfejsa.

Razlog zašto je DI posle postao primarni način realizacije IoC-a je taj što je kod jasniji, čitljiviji.
IoC(Inverzija kontrole)
├── DI(Injektiranje zavisnosti) ← Glavni način realizacije
│ ├── Injektiranje konstruktora
│ ├── Injektiranje polja
│ └── Injektiranje Settera
├── Service Locator pattern
├── Factory pattern
└── Drugi načini realizacijeZašto koristiti IoC?
U svakodnevnom razvoju, ako trebamo da realizujemo određenu funkcionalnost, verovatno nam trebaju barem dva objekta za saradnju, pre Spring-a, svaki objekat bi trebalo sam da kreira novi kada treba njegov saradnik, na primer A treba da koristi B, A tada stvara zavisnost od B, odnosno postoji relacija sprezanja između A i B.
// Tradicionalni način: objekat sam kreira zavisnosti
public class UserService {
private UserDao userDao = new UserDaoImpl(); // Hardkodirana zavisnost
public User getUser(Long id) {
return userDao.findById(id);
}
}Sa Spring-om, kreiranje B se prepušta Spring-u, Spring kreira objekat B i stavlja ga u kontejner, A kaže Spring-u da treba B, Spring izvlači B iz kontejnera i daje A da ga koristi.
// IoC način: zavisnosti se injektiraju spolja
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao; // injektiranje zavisnosti, ne važ konkretna implementacija
public User getUser(Long id) {
return userDao.findById(id);
}
}Š se tiče toga kako je B nastao, A više ne mari, Spring kontejner hoće li preko newnew kreirati B ili preko new kreirati B, svejedno je.
Ovo je prednost IoC-a, smanjuje stepen sprezanja između objekata, tako da svaki objekat fokusira se na sopstvenu poslovnu realizaciju, ne mari se kako su drugi objekti kreirani.
Preporučujem čitanje: Guyaolang: razumevanje Spring IOC-a
- Java vodič za razgovor (plaćeni) uključuje pitanje s prvog intervjuua dnevnog stažiranja Xiaomi 25: kažite vaše razumevanje AOP-a i IoC-a.
- Java vodić za razgovor (plaćeni) uključuje pitanje sa zbirke malih kompanija prijatelja 1 za Java backend intervju: predstavite Spring IoC i AOP?
- Java vodić za razgovor (plaćeni) uključuje pitanje iz zbirke China Merchants Bank prijatelja 6 intervju za China Merchants Bank Network Technology: AOP, IOC/DI u SpringBoot okviru?
- Java vodić za razgovor (plaćeni) uključuje pitanje iz zbirke JD prijatelja 8 intervju: IOC, AOP
- Java vodić za razgovor (plaćeni) uključuje pitanje s prvog intervjuua zaposlenog u Kuaishouu 4: objasnite šta su IOC i AOP? Koje probleme rešavaju? Koja je razlika između IOC i DI?
17.Možete li reći nešto o implementacionom mehanizmu IoC-a?
Dobro, implementacioni mehanizam Spring IoC-a je prilično kompleksan, pokušaću da objasnim ceo proces na što jednostavniji način.

Prvi korak je učitavanje definicionih informacija o Bean-ovima. Spring će skenirati podešene putanje paketa, pronaći sve klase označene anotacijama @Component, @Service, @Repository, a zatim će metapodatke ovih klasa enkapsulirati u BeanDefinition objekte.
// Definicione informacije o Bean-u
public class BeanDefinition {
private String beanClassName; // naziv klase
private String scope; // opseg
private boolean lazyInit; // da li je lenjo učitavanje
private String[] dependsOn; // zavisni Bean-ovi
private ConstructorArgumentValues constructorArgumentValues; // konstruktori parametri
private MutablePropertyValues propertyValues; // vrednosti svojstava
}Drugi korak je priprema Bean fabrike. Spring će kreirati DefaultListableBeanFactory kao Bean fabriku odgovornu za kreiranje i upravljanje Bean-ovima.

Treći korak je instanciranje i inicijalizacija Bean-ova. Ovaj proces je prilično kompleksan, Spring će kreirati instance Bean-ova na osnovu BeanDefinition-a.

Za singleton Bean-ove, Spring će prvo proveriti da li već postoje u kešu, ako ne postoje, kreira novu instancu. Prilikom instanciranja će putem refleksije pozvati konstruktorsku metodu, zatim vrši injektiranje svojstava, i na kraju izvršava povratne metode za inicijalizaciju.
// Pojednostavljeni proces kreiranja Bean-a
public class AbstractBeanFactory {
protected Object createBean(String beanName, BeanDefinition bd) {
// 1. Obrada pre instanciranja
Object bean = resolveBeforeInstantiation(beanName, bd);
if (bean != null) {
return bean;
}
// 2. Stvarno kreiranje Bean-a
return doCreateBean(beanName, bd);
}
protected Object doCreateBean(String beanName, BeanDefinition bd) {
// 2.1 Instanciranje
Object bean = createBeanInstance(beanName, bd);
// 2.2 Popunjavanje svojstava(injektiranje zavisnosti)
populateBean(beanName, bd, bean);
// 2.3 Inicijalizacija
Object exposedObject = initializeBean(beanName, bean, bd);
return exposedObject;
}
}Implementacija injektiranja zavisnosti se uglavnom vrši putem refleksije. Na primer, ako označimo polje anotacijom @Autowired, Spring će prilikom kreiranja Bean-a skenirati ovo polje, zatim će pronaći Bean odgovarajućeg tipa iz kontejnera, i putem refleksije postaviti ga na ovo polje.

Kako razumemete Spring IoC?
IoC je u suštini super fabrika, čiji su proizvodi razni Bean objekti.

Mi putem anotacija @Component, @Service govorimo fabrici: “kakav proizvod treba da proizvedem, kakve karakteristike ima ovaj proizvod, kakve sirovine trebaju”.
Zatim u fabrici postoje razne proizvodne linije, u Spring-u to su razni BeanPostProcessor-i. Na primer AutowiredAnnotationBeanPostProcessor je specijalizovan za obradu @Autowired anotacije.
U fabrici postoje i razni mehanizmi keširanja za čuvanje proizvoda, na primer singletonObjects je magacin gotovih proizvoda, čuva dovršene singleton Bean-ove; earlySingletonObjects je magacin poluprovizoda, služi za rešavanje problema cirkularnih zavisnosti.
// Registarska tabela Spring singleton Bean-ova
public class DefaultSingletonBeanRegistry {
// Keš prvog nivoa: završeni inicijalizovani singleton Bean-ovi
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// Keš drugog nivoa: rano izloženi singleton Bean-ovi(rešavanje cirkularnih zavisnosti)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// Keš trećeg nivoa: fabrika singleton Bean-ova
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
public Object getSingleton(String beanName) {
Object singletonObject = 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;
}
}Najzanimljivije je što je ova fabrika vrlo inteligentna, poznaje relacije zavisnosti između proizvoda. Odlučuje redosled kreiranja Bean-ova na osnovu relacija zavisnosti. Ako otkrije cirkularnu zavisnost, koristi mehanizam keša trećeg nivoa da je veštački reši.
Možete li napisati jednostavan IoC kontejner?
- Prvo definišemo osnovne anotacije, na primer
@Component,@Autowireditd.
// Komponentna anotacija
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}
// Anotacija za automatsko injektiranje
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}- Centralna IoC kontejnerska klasa, odgovorna za skeniranje putanja paketa, kreiranje Bean instanci, i obradu injektiranja zavisnosti.
public class SimpleIoC {
// Bean kontejner
private Map<Class<?>, Object> beans = new HashMap<>();
/**
* Registracija Bean-a
*/
public void registerBean(Class<?> clazz) {
try {
// Kreiranje instance
Object instance = clazz.getDeclaredConstructor().newInstance();
beans.put(clazz, instance);
} catch (Exception e) {
throw new RuntimeException(“Neuspešno kreiranje Bean-a: “ + clazz.getName(), e);
}
}
/**
* Dobavljanje Bean-a
*/
@SuppressWarnings(“unchecked”)
public <T> T getBean(Class<T> clazz) {
return (T) beans.get(clazz);
}
/**
* Injektiranje zavisnosti
*/
public void inject() {
for (Object bean : beans.values()) {
injectFields(bean);
}
}
/**
* Injektiranje polja
*/
private void injectFields(Object bean) {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
try {
field.setAccessible(true);
Object dependency = getBean(field.getType());
field.set(bean, dependency);
} catch (Exception e) {
throw new RuntimeException(“Neuspešno injektiranje: “ + field.getName(), e);
}
}
}
}
}- Primer korišćenja, definišemo neke Bean klase, i registrujemo ih u IoC kontejneru.
// DAO sloj
@Component
class UserDao {
public void save(String user) {
System.out.println(“Čuvanje korisnika: “ + user);
}
}
// Service sloj
@Component
class UserService {
@Autowired
private UserDao userDao;
public void createUser(String name) {
userDao.save(name);
System.out.println(“Korisničko kreiranje završeno”);
}
}
// Test
public class Test {
public static void main(String[] args) {
SimpleIoC ioc = new SimpleIoC();
// Registracija Bean-ova
ioc.registerBean(UserDao.class);
ioc.registerBean(UserService.class);
// Injektiranje zavisnosti
ioc.inject();
// Korišćenje
UserService userService = ioc.getBean(UserService.class);
userService.createUser(“Wang Er”);
}
}- Može se dodati skeniranje komponenti.
import java.lang.reflect.Field;
import java.util.*;
public class SimpleIoC {
private Map<Class<?>, Object> beans = new HashMap<>();
/**
* Skeniranje i registracija komponenti
*/
public void scan(String packageName) {
// Pojednostavljena verzija: ručno dodavanje klasa za skeniranje
List<Class<?>> classes = getClassesInPackage(packageName);
for (Class<?> clazz : classes) {
if (clazz.isAnnotationPresent(Component.class)) {
registerBean(clazz);
}
}
// Injektiranje zavisnosti
inject();
}
/**
* Dobavljanje klasa iz paketa(pojednostavljena implementacija)
*/
private List<Class<?>> getClassesInPackage(String packageName) {
// Na intervjuu možete reći: “Stvarna implementacija zahteva skeniranje classpath-a, ovde je pojednostavljeno”
return Arrays.asList(UserDao.class, UserService.class);
}
private void registerBean(Class<?> clazz) {
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
beans.put(clazz, instance);
} catch (Exception e) {
throw new RuntimeException(“Neuspešno kreiranje Bean-a”, e);
}
}
@SuppressWarnings(“unchecked”)
public <T> T getBean(Class<T> clazz) {
return (T) beans.get(clazz);
}
private void inject() {
for (Object bean : beans.values()) {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
try {
field.setAccessible(true);
Object dependency = getBean(field.getType());
field.set(bean, dependency);
} catch (Exception e) {
throw new RuntimeException(“Neuspešno injektiranje”, e);
}
}
}
}
}
}Srž IoC kontejnera je upravljanje objektima i injektiranje zavisnosti, prvo se definišu anotacije, zatim se realizuju tri ključne metode kontejnera: registracija Bean-ova, dobavljanje Bean-ova, injektiranje zavisnosti; ključno je korišćenje refleksije za kreiranje objekata i injektiranje zavisnosti.
18.Kažite koja je razlika između BeanFactory i ApplicationContext?
BeanFactory se može smatrati “srcem” Spring-a, dok ApplicationContext može biti “kompletan telo” Spring-a.

BeanFactory pruža najosnovnije IoC sposobnosti. To je fabrika Bean-ova, odgovorna za kreiranje i upravljanje Bean-ovima. Koristi lenjo učitavanje, odnosno samo kada stvarno treba da dobije određeni Bean, tada ga kreira.

Njegova glavna metoda je getBean(), odgovorna za vraćanje Bean instance određenog naziva ili tipa iz kontejnera.
public class BeanFactoryExample {
public static void main(String[] args) {
// Kreiranje BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// Ručna registracija Bean definicije
BeanDefinition beanDefinition = new RootBeanDefinition(UserService.class);
beanFactory.registerBeanDefinition(“userService”, beanDefinition);
// Lenjo učitavanje: tek sada se kreira Bean instanca
UserService userService = beanFactory.getBean(“userService”, UserService.class);
}
}ApplicationContext je podinterfejs BeanFactory-a, na osnovu BeanFactory-a proširuje mnogo preduzetnih funkcionalnosti. Ne samo da sadrži sve funkcionalnosti BeanFactory-a, već pruža podršku za internacionalizaciju, mehanizam objavljivanja događaja, AOP, JDBC, ORM okvir integraciju itd.

ApplicationContext koristi režim eager učitavanja, prilikom pokretanja kontejnera kreira sve singleton Bean-ove, iako ovo uzrokuje duže vreme pokretanja, performanse u vreme izvršavanja su bolje.
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
public class ApplicationContextExample {
public static void main(String[] args) {
// Kreiranje ApplicationContext, prilikom pokretanja se kreiraju svi Bean-ovi
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Dobavljanje Bean-a
UserService userService = context.getBean(UserService.class);
// Objavljivanje događaja
context.publishEvent(new CustomEvent(“Hello World”));
}
}Sa aspekta scenarija korišćenja, u stvarnom razvoju se najviše koristi ApplicationContext. AnnotationConfigApplicationContext, WebApplicationContext i sl. su sve implementacije ApplicationContext-a.
Druga važna razlika je upravljanje životnim ciklusom. ApplicationContext će automatski pozvati inicijalizacione i destruktivne metode Bean-a, dok BeanFactory zahteva ručno upravljanje.
U Spring Boot projektima, možemo injektirati ApplicationContext putem @Autowired, ili dobiti ApplicationContext implementacijom ApplicationContextAware interfejsa.

- Java vodič za razgovor (plaćeni) uključuje pitanje drugog intervjua zaposlenog u Meituanu 2 za logističko raspoređivanje: BeanFactory i ApplicationContext
19.🌟Šta radi Spring IoC prilikom pokretanja projekta?
Prva stvar je skeniranje i registracija Bean-ova. IoC kontejner će na osnovu naše konfiguracije, na primer putanje paketa navedene u @ComponentScan, skenirati sve klase označene anotacijama @Component, @Service, @Controller. Zatim će metapodatke ovih klasa upakovati u BeanDefinition objekte, i registrovati ih u BeanDefinitionRegistry kontejnera. U ovoj fazi se samo sakupljaju informacije, još uvek se ne kreiraju objekti.

Druga stvar je instanciranje i injektiranje Bean-ova. Ovo je najključniji proces, IoC kontejner će početi sa kreiranjem instanci Bean-ova po redosledu zavisnosti. Za singleton Bean-ove, kontejner će putem refleksije pozvati konstruktorsku metodu za kreiranje instance, zatim vrši injektiranje svojstava, i na kraju izvršava inicijalizacione povratne metode.

Prilikom injektiranja zavisnosti, kontejner će na osnovu anotacija @Autowired, @Resource itd., injektirati odgovarajuće objekte zavisnosti u ciljni Bean. Na primer, ako UserService treba UserDao, kontejner će instancu UserDao injektirati u UserService.
Kažite koje su načini instanciranja Spring Bean-ova?
Spring pruža 4 načina za instanciranje Bean-ova, kako bi zadovoljlio različite scenarije.
Prvi način je instanciranje putem konstruktora, ovo je najčešće korišćeni način. Kada označimo klasu anotacijama @Component, @Service, Spring podrazumevano kreira instancu putem bezparametarskog konstruktora. Ako klasa ima samo jedan konstruktur sa parametrima, Spring će automatski izvršiti injektiranje konstruktora.
@Service
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) { // injektiranje konstruktora
this.userDao = userDao;
}
}Drugi način je instanciranje putem statičke fabrik metode. Ponekad je kreiranje objekta kompleksno, napišemo statičku fabrik metodu za kreiranje, i označimo je @Bean anotacijom. Spring će pozvati ovu statičku metodu da dobije Bean instancu.
@Configuration
public class AppConfig {
@Bean
public static DataSource createDataSource() {
// Kompleksna logika kreiranja DataSource-a
return new HikariDataSource();
}
}Treći način je instanciranje putem metode instance fabrike. Ovaj način prvo kreira objekat fabrike, zatim putem metode fabrike kreira Bean:
@Configuration
public class AppConfig {
@Bean
public ConnectionFactory connectionFactory() {
return new ConnectionFactory();
}
@Bean
public Connection createConnection(ConnectionFactory factory) {
return factory.createConnection();
}
}Četvrti način je instanciranje putem FactoryBean interfejsa. Ovo je specijalan interfejs koji Spring pruža, posebno koristan kada trebamo da kreiramo kompleksne objekte:
@Component
public class MyFactoryBean implements FactoryBean<MyObject> {
@Override
public MyObject getObject() throws Exception {
// Kompleksna logika kreiranja objekta
return new MyObject();
}
@Override
public Class<?> getObjectType() {
return MyObject.class;
}
}U stvarnom radu, najčešće se koristi instanciranje putem konstruktora, jer je jednostavno i direktno. Fabrik metode se uglavnom koriste u scenarijima koji zahtevaju kompleksnu inicijalizacionu logiku, na primer za bazu podataka connection pool, red poruka itd. FactoryBean se uglavnom koristi u razvoj okvira ili kada treba dinamičko kreiranje objekata.
Spring prilikom instanciranja automatski bira odgovarajući način na osnovu Bean definicije, mi kao razvojni programeri uglavnom putem anotacija i konfiguracija govorimo Spring-u kako da kreira objekte.
- Java vodič za razgovor (plaćeni) uključuje pitanje drugog tehničkog intervjua Huawei prijatelja 8: kažite načine instanciranja Spring Bean-ova
- Java vodič za razgovor (plaćeni) uključuje pitanje drugog intervjua zaposlenog u Meituanu 2 za logističko raspoređivanje: koje metode ima obrada Bean-ova?
AOP
20.🌟Kažite šta je AOP?
AOP, odnosno Aspect-Oriented Programming, jednostavno rečeno, AOP izdvaja isti kod iz poslovne logike u nezavisan modul, čime se poslovna logika čisti i preglednija.

----Ovaj deo nije neophodno pamćenje za intervju, olakšava razumevanje start----
Navedimo jednostavan primer, pretpostavimo da imamo mnogo Service metoda, svaka metoda treba da beleži izvršne loge, proverava dozvole, upravlja transakcijama itd. Bez AOP-a, morali bismo da pišemo ovakav kod u svakoj metodi:
public void createUser(User user) {
log.info("Počinje izvršenje createUser metode");
// Provera dozvola
if (!hasPermission()) {
throw new SecurityException("Nema dozvole");
}
// Otvaranje transakcije
transactionManager.begin();
try {
// Stvarna poslovna logika
userDao.save(user);
transactionManager.commit();
log.info("createUser metoda uspešno izvršena");
} catch (Exception e) {
transactionManager.rollback();
log.error("createUser metoda neuspešno izvršena", e);
throw e;
}
}Ako svaku metodu napišemo ovako, kod postaje veoma nepregledan, AOP rešava ovaj problem, omogućava nam da izvucemo ove presečne tačke (npr. logovi, dozvole, transakcije itd.) iz poslovnog koda.
Tako možemo definisati aspekt, u kome ćemo jedinstveno obrađivati te presečne tačke:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
log.info("Počinje izvršenje metode: " + joinPoint.getSignature().getName());
}
@AfterReturning("execution(* com.example.service.*.*(..))")
public void logAfterReturning(JoinPoint joinPoint) {
log.info("Metoda uspešno izvršena: " + joinPoint.getSignature().getName());
}
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
log.error("Metoda neuspešno izvršena: " + joinPoint.getSignature().getName(), ex);
}
}Zatim se poslovni kod postaje vrlo čist:
public void createUser(User user) {
// samo se fokusira na poslovnu logiku, ne brinem o logovima, dozvolama, transakcijama itd.
userDao.save(user);
}----Ovaj deo nije neophodno pamćenje za intervju olakšava razumevanje end----
Sa tehničkog aspekta implementacije, AOP se uglavnom realizuje putem dinamičkog proksija. Ako ciljna klasa implementira interfejs, koristi se JDK dinamički proksi; ako ne implementira interfejs, koristi se CGLIB za kreiranje proksija podklase. Proksi objekat će ubaciti logiku aspekta definisanu od strane korisnika pre i posle izvršenja metoda.

Koje su ključne koncepte Spring AOP-a?
Spring AOP je konkretna implementacija AOP-a, po redu važnosti u radu/učenju kažu:

①,Aspekt:Klasa koju definišemo, sadrži informacije o kada, gde i šta da se izvrši. Na primer, možemo definisati log aspekt, posebno odgovoran za beleženje izvršenja metoda. U Spring-u, označavamo aspekt anotacijom @Aspect.
②,Tačka presecanja:Definiše gde se primenjuje logika aspekta. Jednostavno rečeno, govorimo Spring-u gde da primeni ovaj aspekt. Na primer, možemo definisati izraz tačke presecanja da odgovara svim metodama Service sloja ili svim metodama u određenom paketu. U Spring-u se definiše anotacijom @Pointcut, obično se pišu izrazi poput execution( com.example.service..*(..)).
③,Obaveštenje:Konkretna logika za izvršenje u aspektu. Ima nekoliko tipova: @Before se izvršava pre metoda, @After se izvršava posle metoda, @Around je okolno obaveštenje koje se može izvršiti pre i posle metoda, @AfterReturning se izvršava posle normalnog povratka metoda, @AfterThrowing se izvršava posle bacanja izuzetka metoda. Najčešće koristim @Around jer je najfleksibilniji, može kontrolisati da li se metoda izvršava, može modifikovati parametre i povratne vrednosti.
④,Tačka povezivanja:Presrečena tačka, pošto Spring podržava samo tipove tačaka povezivanja metoda, u Spring-u, tačka povezivanja se odnosi na metodu koja je presrečena, iako tačka povezivanja može biti i polje ili konstruktor.
⑤,Upletanje:Proces primenjivanja logike aspekta na ciljni objekat. Spring AOP realizuje upletanje u vreme izvršavanja putem dinamičkog proksija, kada dobijamo Bean iz Spring kontejnera, ako ovaj Bean treba da bude obrađen aspektom, Spring će vratiti proksi objekat.
⑥,Ciljni objekat:Objekat koji se obrađuje aspektom, odnosno Service, Controller i sl. klase koje pišemo. Spring AOP će upleti logiku aspekta u ciljni objekat.
Logički odnos između njih je ovakav:
Aspekt(Aspect)
├── Tačka presecanja(Pointcut)─── Definiše gde se izvršava
└── Obaveštenje(Advice) ─── Definiše kada i šta se izvršava
├── @Before
├── @After
├── @AfterReturning
├── @AfterThrowing
└── @Around
Ciljni objekat(Target)──→ Proksi objekat(Proxy)──→ Upletanje(Weaving)
↑ ↓
Tačka povezivanja(Join Point) Klijentski pozivKoje vrste upletanja Spring AOP ima?
Postoje tri glavne vrste upletanja, po redu vremena izvršenja kažu:

Upletanje u vreme kompajliranja podrazumeva upletanje logike aspekta u ciljnu klasu prilikom kompajliranja Java izvornog koda. Tipična implementacija ovakvog načina je AspectJ kompajler. Prilikom kompajliranja direktno modifikuje bajt kod, ubacuje logiku aspekta u ciljnu metodu.
// Izvorni kod
@Aspect
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Pre metode: " + joinPoint.getSignature().getName());
}
}
@Service
public class UserService {
public void saveUser(String username) {
System.out.println("Čuvanje korisnika: " + username);
}
}Generisana class datoteka već sadrži logiku aspekta, u vreme izvršavanja nije potreban dodatni mehanizam proksija.
// Kod automatski generisan od strane kompajlera
public class UserService {
public void saveUser(String username) {
// Upleteni kod aspekta
System.out.println("Pre metode: saveUser");
// Izvorni poslovni kod
System.out.println("Čuvanje korisnika: " + username);
}
}Prednost upletanja u vreme kompajliranja je najbolja performansa, jer nema režije proksija, ali mana je što zahteva upotrebu specijalnog kompajlera i prilično je kompleksno, u Spring projektima se ne koristi često.
Upletanje u vreme učitavanja klase odvija se prilikom učitavanja class datoteke u JVM. Ovaj način se realizuje putem Java Instrumentation API-ja ili prilagođenog ClassLoader-a, pre modifikacije bajt koda pre učitavanja klase u JVM.
public class WeavingClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classBytes = loadClassBytes(name);
// Ovde vršimo upletanje bajt koda
byte[] wovenBytes = weaveAspects(classBytes);
return defineClass(name, wovenBytes, 0, wovenBytes.length);
}
private byte[] weaveAspects(byte[] classBytes) {
// Korišćenje ASM ili drugih biblioteka za manipulaciju bajt kodom
return classBytes;
}
}AspectJ-ov Load-Time Weaving je tipična implementacija ovog načina. Fleksibilniji od upletanja u vreme kompajliranja, ali konfiguracija je prilično kompleksna, potrebno je navesti Java agent u JVM startnim parametrima, Spring takođe podržava, ali se ne koristi baš često.
# JVM startni parametri
java -javaagent:aspectjweaver.jar -jar myapp.jarUpletanje u vreme izvršavanja je najčešći način u Spring-u, odnosno realizuje se putem dinamičkog proksija. Spring AOP koristi ovaj način. Kada se Spring kontejner pokrene, ako otkrije da određeni Bean treba da bude obrađen aspektom, kreiraće proksi objekat za taj Bean. Ako ciljna klasa implementira interfejs, Spring će koristiti JDK dinamičku tehnologiju proksija.
// Interfejs
public interface UserService {
void saveUser(String username);
}
// Implementacija
@Service
public class UserServiceImpl implements UserService {
@Override
public void saveUser(String username) {
System.out.println("Čuvanje korisnika: " + username);
}
}
// Proksi automatski kreiran od strane Spring(pseudo-kod)
public class UserServiceProxy implements UserService {
private UserService target;
private List<Advisor> advisors;
@Override
public void saveUser(String username) {
// Izvršavanje prednjeg obaveštenja
for (Advisor advisor : advisors) {
if (advisor.getPointcut().matches(this.getClass().getMethod("saveUser", String.class))) {
advisor.getAdvice().before();
}
}
// Izvršavanje ciljne metode
target.saveUser(username);
// Izvršavanje zadnjeg obaveštenja
for (Advisor advisor : advisors) {
advisor.getAdvice().after();
}
}
}Ako ciljna klasa ne implementira interfejs, koristi se CGLIB za kreiranje podklase kao proksi. Prednost upletanja u vreme izvršavanja je jednostavna implementacija, ne zahteva specijalne kompajlere ili JVM konfiguraciju, mana je postojanje određenih performanskih režija, jer svaki poziv metoda prolazi kroz proksi.
// Klasa bez interfejsa
@Service
public class OrderService {
public void createOrder(String orderId) {
System.out.println("Kreiranje narudžbine: " + orderId);
}
}
// Proksi podklase generisan od strane CGLIB(pseudo-kod)
public class OrderService$$EnhancerByCGLIB$$12345 extends OrderService {
private MethodInterceptor interceptor;
@Override
public void createOrder(String orderId) {
// Izvršavanje logike aspekta putem MethodInterceptor
interceptor.intercept(this, getMethod("createOrder"), new Object[]{orderId},
new MethodProxy() {
@Override
public Object invokeSuper(Object obj, Object[] args) {
return OrderService.super.createOrder((String) args[0]);
}
});
}
}Spring AOP podrazumevano koristi upletanje u vreme izvršavanja, korišćenje je veoma jednostavno, samo treba dodati @Aspect anotaciju i odgovarajuće obaveštenje. Iako su performanse lošije od upletanja u vreme kompajliranja, za većinu poslovnih scenarija ova režija je potpuno prihvatljiva.
// Proces kreiranja proksija Spring AOP-a
@Configuration
@EnableAspectJAutoProxy // Omogućava automatski AOP proksi
public class AopConfig {
}
// Unutrašnja logika kreiranja proksija Spring(pojednostavljeno)
public class DefaultAopProxyFactory implements AopProxyFactory {
@Override
public AopProxy createAopProxy(AdvisedSupport config) {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// Korišćenje CGLIB proksija
return new CglibAopProxy(config);
} else {
// Korišćenje JDK dinamičkog proksija
return new JdkDynamicAopProxy(config);
}
}
}Šta je AspectJ?
AspectJ je AOP okvir koji može učiniti mnoge stvari koje Spring AOP ne može, na primer upletanje aspekata u vreme kompajliranja, posle kompajliranja i u vreme učitavanja klase. Pruža mnogo kompleksnih izraza tačaka presecanja i tipova obaveštenja.

Spring AOP podržava samo upletanje na nivou metoda, i može presretati samo Bean-ove upravljane od strane Spring kontejnera. Ali AspectJ može presretati pozive metoda bilo kog Java objekta, pristup poljima, izvršenje konstruktora, obradu izuzetaka itd.
// Spring AOP može samo ovo
@Aspect
@Component
public class SpringAopAspect {
// ✅ Može presreti: pozive public metoda
@Around("execution(public * com.example.service.*.*(..))")
public Object aroundPublicMethod(ProceedingJoinPoint pjp) {
return pjp.proceed();
}
// ❌ Ne može presreti: pristup poljima
// ❌ Ne može presreti: konstruktore
// ❌ Ne može presreti: privatne metode
// ❌ Ne može presreti: statičke metode
}Koje vrste obaveštenja Spring AOP ima?
Spring AOP pruža više vrsta obaveštenja, dozvoljava nam da ubacimo logiku u različite faze izvršenja metoda. Često korišćene vrste obaveštenja su:
- Prednje obaveštenje (@Before)
- Obaveštenje o povratku (@AfterReturning)
- Obaveštenje o izuzetku (@AfterThrowing)
- Zadnje obaveštenje (@After)
- Okolno obaveštenje (@Around)

Prednje obaveštenje se izvršava pre izvršenja ciljne metode. Ova vrsta obaveštenja je prilično jednostavna, uglavnom se koristi za pripremne radnje, na primer validaciju parametara, proveru dozvola, beleženje početka izvršenja metode itd. Prednje obaveštenje ne može sprečiti izvršenje ciljne metode, niti može modifikovati parametre metoda, samo može vršiti dodatne operacije pre izvršenja metode. U projektima ga često koristimo za beleženje operativnih logova, na primer beleženje ko je u koje vreme pozivao koju metodu.
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
// Ispis naziva metode i parametara
System.out.println("Poziv metode: " + joinPoint.getSignature().getName());
System.out.println("Parametri: " + Arrays.toString(joinPoint.getArgs()));
}
}Zadnje obaveštenje se izvršava posle završetka izvršenja ciljne metode, bez obzira da li se metoda normalno vratila ili bacila izuzetak. Ova vrsta obaveštenja uglavnom služi za čišćenje, na primer oslobađanje resursa, beleženje završetka izvršenja metode itd. Treba napomenuti da zadnje obaveštenje ne dobija povratnu vrednost metode, niti može uhvatiti informacije o izuzetku, samo čisti posle izvršenja metode.
@Aspect
@Component
public class LoggingAspect {
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
// Ispis loga završetka izvršenja metode
System.out.println("Metoda završena: " + joinPoint.getSignature().getName());
}
}Obaveštenje o povratku se izvršava posle normalnog povratka ciljne metode. Ova vrsta obaveštenja može dobiti povratnu vrednost metode, možemo specifikirati parametar returning u anotaciji za prijem povratne vrednosti. Obaveštenje o povratku često koristimo za dalju obradu na osnovu rezultata povrata, na primer keširanje povratne vrednosti metode, slanje obaveštenja na osnovu povratne vrednosti itd. Ako metoda baci izuzetak, obaveštenje o povratku se neće izvršiti.
@Aspect
@Component
public class LoggingAspect {
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
// Ispis loga završetka izvršenja metode
System.out.println("Metoda završena: " + joinPoint.getSignature().getName());
// Ispis povratne vrednosti metode
System.out.println("Povratna vrednost: " + result);
}
}Obaveštenje o izuzetku se izvršava posle bacanja izuzetka ciljne metode. U anotaciji možemo specifikovati parametar throwing za prijem objekta izuzetka. Obaveštenje o izuzetku uglavnom služi za obradu i beleženje izuzetaka, na primer beleženje grešaka, slanje upozorenja, statistiku izuzetaka itd. Treba napomenuti da obaveštenje o izuzetku ne može obraditi izuzetak, izuzetak će i dalje biti bačen naviše.
@Aspect
@Component
public class LoggingAspect {
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
// Ispis naziva metode i informacija o izuzetku
System.out.println("Metoda izbacila izuzetak: " + joinPoint.getSignature().getName());
System.out.println("Informacije o izuzetku: " + ex.getMessage());
}
}Okolno obaveštenje je najmoćnija i najčešće korišćena vrsta obaveštenja. Može izvršavati logiku pre i posle metode, može kontrolisati da li će se ciljna metoda izvršiti, može modifikovati parametre i povratne vrednosti metoda. Metoda okolnog obaveštenja mora primiti ProceedingJoinPoint parametar, pozivom njene proceed() metode se izvršava ciljna metoda.
U Tehnički projektu se uglavnom koristi okolno obaveštenje za realizaciju aspekata.

Ako ima više aspekata, može se specifikovati redosled anotacijom @Order, što je manji broj, to je viši prioritet. Primer koda:
@Aspect
@Component
public class WebLogAspect {
private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
@Pointcut("@annotation(cn.fighter3.spring.aop_demo.WebLog)")
public void webLog() {}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// Počinje ispisivanje loga zahteva
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// Ispis relevantnih parametara zahteva
logger.info("========================================== Start ==========================================");
// Ispis URL zahteva
logger.info("URL : {}", request.getRequestURL().toString());
// Ispis HTTP metoda
logger.info("HTTP Method : {}", request.getMethod());
// Ispis punog puta kontrollera i izvršne metode
logger.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
// Ispis IP zahteva
logger.info("IP : {}", request.getRemoteAddr());
// Ispis ulaznih parametara zahteva
logger.info("Request Args : {}",new ObjectMapper().writeValueAsString(joinPoint.getArgs()));
}
@After("webLog()")
public void doAfter() throws Throwable {
// Posle završetka ispis separator, olakšava pregled
logger.info("=========================================== End ===========================================");
}
@Around("webLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//Početno vreme
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
// Ispis izlaznih parametara
logger.info("Response Args : {}", new ObjectMapper().writeValueAsString(result));
// Vreme izvršavanja
logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
return result;
}
}Kad se dešava Spring AOP?
Spring AOP se dešava u fazi inicijalizacije Bean-a, konkretno u fazi post-processing životnog ciklusa Bean-a.
Posle završetka instanciranja Bean-a i injektiranja svojstava, Spring će pozvati metodu postProcessAfterInitialization svih BeanPostProcessor-a, kreiranje AOP proksija se upravo završava u ovoj fazi.

Jednostavno sažimanje AOP-a
AOP, odnosno Aspect-Oriented Programming, je programski paradiigma, cilj je poboljšanje modularnosti koda. Na primer može izdvojiti beleženje logova, upravljanje transakcijama itd. kako bi poboljšao ponovljivost koda.
Ključni koncepti AOP-a uključuju aspekt, tačku povezivanja, obaveštenje, tačku presecanja i upletanje itd.
① Logovi, transakcije itd. mogu se izdvojiti kao aspekti, mogu se deklarisati na metodama klase. @Transactional anotacija je tipična AOP primena, realizuje upravljanje transakcijama putem AOP-a. Mi samo dodamo @Transactional anotaciju na metodu, Spring će dodati logiku upravljanja transakcijama pre i posle izvršenja metode.
② Spring AOP je baziran na proksiju, podrazumevano koristi JDK dinamički proksi i CGLIB proksi za realizaciju AOP-a.
③ Način upletanja Spring AOP-a je u vreme izvršavanja, dok AspectJ podržava upletanje u vreme kompajliranja, u vreme učitavanja klase.
Koji je odnos između AOP-a i OOP-a?
AOP i OOP su komplementarne programerske ideje:
- OOP enkapsulira podatke i ponašanje kroz klase i objekte, fokusira se na ključnu poslovnu logiku.
- AOP pruža mehanizam za rešavanje presečnih tačaka(npr. logovi, dozvole, transakcije itd.), centralizovano upravlja ovu logiku.
- Java vodič za razgovor (plaćeni) uključuje pitanje prvog intervju-a za Tencent Java backend stažu: kažite princip AOP-a.
- Java vodič za razgovor (plaćeni) uključuje pitanje prvog intervju-a dnevnog stažiranja Xiaomi 25: kažite vaše razumevanje AOP-a i IoC-a.
- Java vodič za razgovor (plaćeni) uključuje pitanje prvog tehničkog intervju-a zaposlenog u Kuaishouu 7 za Java backend: recite implementacioni princip Spring AOP-a
- Java vodič za razgovor (plaćeni) uključuje pitanje prijatelja 1 iz zbirke malih kompanija za Java backend intervju: predstavite Spring IoC i AOP?
- Java vodič za razgovor (plaćeni) uključuje pitanje prijatelja 6 iz zbirke China Merchants Bank intervju za China Merchants Bank Network Technology: AOP, IOC/DI u SpringBoot okviru?
- Java vodič za razgovor (plaćeni) uključuje pitanje prvog intervju-a zaposlenog u Meituanu 4: kad se dešava Spring AOP
- Java vodič za razgovor (plaćeni) uključuje pitanje prvog intervju-a zaposlenog u Li Auto 2: da li razumete koncept Spring AOP? Koji je odnos između AOP-a i OOP-a?
memo:7. jula 2025. godine izmenjeno do ovde, prijatelj je tražio detaljan plan učenja, proveo sam jutro u organizovanju tromesečnog plana sprinta, uključujući osnovne znanja, algoritme, rasporede projekata, već stavljeno u Java vodič za razgovor, prijatelji koji trebaju mogu preuzeti za referencu.

21.🌟Koje su scenariji primene AOP-a?
Odgovor: AOP ima mnogo scenarija primene u stvarnom radu/kodiranju učenju, po redu učestalosti kažu nekoliko glavnih.
Upravljanje transakcijama je najčešće korišćeni scenarij, gotovo svaki projekt ga koristi. Samo dodajemo @Transactional anotaciju na Service metodu, Spring će automatski upravljati otvaranjem, potvrđivanjem i poništavanjem transakcija.

Beleženje logova je takođe vrlo česta primena. U Tehnički praktični projekat, AOP se koristi za ispis ulaznih i izlaznih parametara interfejsa, vreme izvršenja, olakšava kasnije traženje grešaka i optimizaciju performansi.

----Ovaj deo nije neophodno pamćenje za intervju olakšava razumevanje start----
Prvi korak, definišemo @MdcDot anotaciju:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MdcDot {
String bizCode() default "";
}Drugi korak, konfigurišemo MdcAspect aspekt, presrećemo metode ili klase sa @MdcDot anotacijom, vršimo MDC operacije pre i posle izvršenja metode, beležimo vreme izvršenja metoda.

Treći korak, dodajemo @MdcDot anotaciju tamo gde je potrebno.

Četvrti korak, kada se pozove interfejs, možemo videti odgovarajuće izvršne logove.
2023-06-16 11:06:13,008 [http-nio-8080-exec-3] INFO |00000000.1686884772947.468581113|101|c.g.p.forum.core.mdc.MdcAspect.handle(MdcAspect.java:47) - Vreme izvršenja metode: com.github.paicoding.forum.web.front.article.rest.ArticleRestController#recommend = 47----Ovaj deo nije neophodno pamćenje za intervju olakšava razumevanje end----
Pored toga, postoje scenariji kontrole dozvola, praćenje performansi, keširanje itd. Ukratko, svaka opšta logika koja se ponavlja na više mesta može se realizovati AOP-om.
- Java vodič za razgovor (plaćeni) uključuje pitanje prvog tehničkog intervju-a zaposlenog u JD-u 5 za Java backend: scenariji primene AOP-a
- Java vodič za razgovor (plaćeni) uključuje pitanje prvog intervju-a zaposlenog u Li Auto 2: koje su scenarije korišćenja AOP-a?
- Java vodič za razgovor (plaćeni) uključuje pitanje intervju-a zaposlenog u JD-u 9: kako se koristi AOP u projektu
22.Koja je razlika između Spring AOP i AspectJ?
Spring AOP podržava samo upletanje na nivou metoda, i može presretati samo Bean-ove upravljane od strane Spring kontejnera. Ali AspectJ može uplesti skoro svuda, uključujući metode, polja, konstruktore, obradu izuzetaka itd.

Sa aspekta implementacionog mehanizma, Spring AOP je realizovan na osnovu dinamičkog proksija, u vreme izvršavanja kreira proksi za ciljni objekat, putem proksija izvršava logiku aspekta. AspectJ je realizovan putem upletanja bajt koda, direktno modifikuje bajt kod ciljne klase, upliće logiku aspekta u ciljnu metodu.
U stvarnim projektima, većinu vremena koristimo Spring AOP, jer zadovoljava većinu potreba i jednostavan je za korišćenje. Samo kada naiđemo na probleme koje Spring AOP ne može rešiti, na primer treba uplesti metode iz treće strane jar datoteke, ili pratiti polja, tada razmatramo uvođenje AspectJ-a.
Spring AOP pozajmljuje mnogo koncepata i anotacija od AspectJ-a, @Aspect, @Pointcut itd. anotacije koje koristimo u Spring-u, zapravo su definisane od strane AspectJ-a.
23.Koja je razlika između AOP-a i refleksije?(dopuna)
Dopunjeno 27. jula 2024. godine.
Refleksija služi da program može da ispituje i upravlja sopstvenom strukturom, na primer dobavljanje informacija o klasi, pozivanje metoda, pristup poljima itd. AOP služi da dinamički doda dodatno ponašanje metodama bez modifikacije poslovnog koda, na primer beleženje logova, upravljanje transakcijama itd.
Sa tehničkog aspekta implementacije, refleksija je funkcionalnost koju sam Java jezik pruža, realizuje se putem API-ja iz paketa java.lang.reflect. AOP obično zahteva podršku okvira, na primer Spring AOP je realizovan putem dinamičkog proksija, a dinamički proksi je zasnovan na refleksiji.
- Java vodič za razgovor (plaćeni) uključuje pitanje intervju-a zaposlenog u Dewu 9 originalno pitanje intervju-a: bez Spring-a, recite o refleksiji i dinamičkom proksiju? Kako se realizuju tri režima proksija?
Koja je razlika između AOP-a i dekoratorskog obrasca?
AOP i dekoratorski obrazac služe da dinamički dodaju dodatno ponašanje objektima bez modifikacije originalnog koda.
Dekoratorski obrazac se realizuje kreiranjem omotne klase, ova omotna klasa drži referencu na dekorisani objekat i dodaje dodatnu logiku prilikom pozivanja metoda. Dekoratorski obrazac obično zahteva ručno pisanje omotnih klasa, pogodan za pojačavanje pojedinačnih objekata.
// Interfejs osnovne komponente
interface Component {
void operation();
}
// Konkretna komponenta
class ConcreteComponent implements Component {
public void operation() {
System.out.println("Izvršenje osnovne operacije");
}
}
// Bazna klasa dekoratora
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
// Konkretni dekorator
class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
public void operation() {
addedBehavior();
super.operation();
addedBehavior();
}
private void addedBehavior() {
System.out.println("Dodana nova funkcionalnost");
}
}24.🌟Koja je razlika između JDK dinamičkog proksija i CGLIB proksija?
JDK dinamički proksi i CGLIB proksi su dva načina kreiranja proksi objekata u Spring AOP-u.

Sa aspekta uslova korišćenja, JDK dinamički proksi zahteva da ciljna klasa implementira barem jedan interfejs, jer kreira proksi na osnovu interfejsa. CGLIB proksi ne zahteva da ciljna klasa implementira interfejs, on kreira proksi nasleđivanjem ciljne klase.
Ovo je najosnovnija razlika između njih. Na primer, ako imamo TransferService interfejs i TransferServiceImpl implementacionu klasu, ako koristimo JDK dinamički proksi, kreirani proksi objekat će implementirati TransferService interfejs;

Ako koristimo CGLIB, proksi objekat će nasleđivati TransferServiceImpl klasu.

Sa aspekta implementacionog principa, JDK dinamički proksi je podržan od strane Jave, putem refleksije dinamički kreira proksi klasu koja implementira specifikovani interfejs u vreme izvršavanja. Kada pozovemo metodu proksi objekta, poziv se prenosi na invoke metodu InvocationHandler-a, u ovoj metodi možemo ubaciti logiku aspekta, zatim putem refleksije pozivamo stvarnu metodu ciljnog objekta.
public class JdkProxyExample {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy1, method, args1) -> {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args1);
System.out.println("After method: " + method.getName());
return result;
}
);
proxy.findUser(1L);
}
}CGLIB je biblioteka treće strane za generisanje bajt koda, putem ASM bajt kod okvira dinamički generiše podklasu ciljne klase, zatim prepisuje metodu roditelja da ubaci logiku aspekta.
public class CglibProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserController.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method: " + method.getName());
return result;
}
});
UserController proxy = (UserController) enhancer.create();
proxy.getUser(1L);
}
}Izabrati CGLIB ili JDK dinamički proksi?
Ako ciljni objekat ne implementira nijedan interfejs, može se koristiti samo CGLIB proksi, na primer klase Controller sloja.```java // Kontroler koji ne implementira interfejs @RestController public class ArticleController { @MdcDot(bizCode = "article.create") public ResponseVo<String> create(@RequestBody ArticleReq req) { // Poslovna logika } }
Ako ciljni objekat implementira interfejs, obično se preferira JDK dinamički proxy, na primer klase u Service sloju, obično prvo definišu interfejs, a zatim implementiraju interfejs.
```java
// Definicija interfejsa
public interface ArticleService {
void saveArticle(Article article);
}
// Implementacija
@Service
public class ArticleServiceImpl implements ArticleService {
@Transactional(rollbackFor = Exception.class)
@Override
public void saveArticle(Article article) {
// Poslovna logika
}
}Posle Spring Boot 2.0, Spring AOP podrazumevano koristi CGLIB proxy. Ovo je zato što Spring Boot kao framework koji teži ka “dogovor je važniji od konfiguracije”, bira CGLIB, može da pojednostani mentalni teret programera, i izbegne probleme nevažećeg AOP-a zbog zaboravljanja implementacije interfejsa.

Da li znate da koristite JDK dinamički proxy?
Da.
Pretpostavimo da imamo takvu malu scenu, korisnička služba preusmerava, rešava probleme korisnika:

Možemo da koristimo JDK dinamički proxy da realizujemo ovu scenu. Jezgro JDK dinamičkog proxy-ja je kroz mehanizam refleksije u vreme izvršavanja kreirati proxy klasu koja implementira specifikovani interfejs.

Prvi korak, kreirajte interfejs.
public interface ISolver {
void solve();
}Drugi korak, implementirajte interfejs.
public class Solver implements ISolver {
@Override
public void solve() {
System.out.println("Čudo se gubi iz kose dok rešavam problem……");
}
}Treći korak, koristite refleksiju da generišete proxy ciljnog objekta, ovde sam koristio anonimnu unutrašnju klasu da prepisem InvocationHandler metodu.
public class ProxyFactory {
// Održavamo ciljni objekat
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// Generišemo proxy objekat za ciljni objekat
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Kako mogu da vam pomognem?");
// Pozovite metodu ciljnog objekta
Object returnValue = method.invoke(target, args);
System.out.println("Problem je rešen!");
return null;
}
});
}
}Četvrti korak, generišite instancu proxy objekta, pozovite metodu ciljnog objekta kroz proxy objekat.
public class Client {
public static void main(String[] args) {
// Ciljni objekat: programer
ISolver developer = new Solver();
// Proxy: devojka za korisničku službu
ISolver csProxy = (ISolver) new ProxyFactory(developer).getProxyInstance();
// Ciljna metoda: rešavanje problema
csProxy.solve();
}
}Da li znate da koristite CGLIB dinamički proxy?
Da.

Prvi korak: definišite ciljnu klasu Solver, definišite metodu solve, simulirajte ponašanje rešavanja problema. Ciljna klasa ne mora da implementira nijedan interfejs, što je različito od zahteva JDK dinamičkog proxy-ja.
public class Solver {
public void solve() {
System.out.println("Čudo se gubi iz kose dok rešavam problem……");
}
}Drugi korak: kreirajte proxy fabriku ProxyFactory, koristite CGLIB Enhancer klasu da generišete podklasu ciljne klase (proxy objekat). CGLIB nam dozvoljava da u vreme izvršavanja dinamički kreiramo proxy klasu koja nasleđuje ciljnu klasu, i prepisemo ciljnu metodu.
public class ProxyFactory implements MethodInterceptor {
// Održavamo ciljni objekat
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// Generišemo proxy objekat za ciljni objekat
public Object getProxyInstance() {
// Alatka
Enhancer en = new Enhancer();
// Podesimo roditeljsku klasu
en.setSuperclass(target.getClass());
// Podesimo callback funkciju
en.setCallback(this);
// Kreiramo podklasu objekta proxy
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Kako mogu da vam pomognem?");
// Izvršimo metodu ciljnog objekta
Object returnValue = method.invoke(target, args);
System.out.println("Problem je rešen!");
return null;
}
}Treći korak: kreirajte klijent Client, dobavite proxy objekat i pozovite ciljnu metodu.
public class Client {
public static void main(String[] args) {
// Ciljni objekat: programer
Solver developer = new Solver();
// Proxy: devojka za korisničku službu
Solver csProxy = (Solver) new ProxyFactory(developer).getProxyInstance();
// Ciljna metoda: rešavanje problema
csProxy.solve();
}
}
- Java intervju vodič (plaćeni) sadrži originalno pitanje FanRuang učesnika 3 Java pozadinski prvi intervju: princip cglib-a
- Java intervju vodič (plaćeni) sadrži originalno pitanje Tencent iskustva učesnika 22 letnja praksa prvi intervju: princip implementacije Spring AOP
- Java intervju vodič (plaćeni) sadrži originalno pitanje Xiaomi iskustva učesnika F intervju: razlika dva dinamička proxy-ja
- Java intervju vodič (plaćeni) sadrži originalno pitanje ByteDance iskustva učesnika 8 Java pozadinski praktični prvi intervju: kako je spring aop implementiran
- Java intervju vodič (plaćeni) sadrži originalno pitanje Tencent Cloud Smart iskustva učesnika 20 drugi intervju: koji je osnovni princip spring aop-a?
- Java intervju vodič (plaćeni) sadrži originalno pitanje Meituan iskustva učesnika 3 Java pozadinski tehnološki prvi intervju: refleksioni mehanizam jav-e, scenariji primene refleksije, princip implementacije AOP, šta je razlika između dinamičkog proxy-ja i refleksije
- Java intervju vodič (plaćeni) sadrži originalno pitanje BYD iskustva učesnika 12 Java tehnički intervju: predstavite proxy, razlika između jdk i cglib
- Java intervju vodič (plaćeni) sadrži originalno pitanje Kuaishou učesnika 4 prvi intervju: princip implementacije Spring AOP? Implementacija i razlika između JDK dinamičkog proxy-ja i CGLib dinamičkog proxy-ja? Sada treba da statistički pratimo tačno vreme izvršavanja metode, kako koristiti AOP da to realizujemo?
- Java intervju vodič (plaćeni) sadrži originalno pitanje Li Auto iskustva učesnika 2 prvi intervju: da li znate kako se AOP osnova radi?
memo: 10. jula 2025. izmenjeno do ovde, danas sam prilikom uređivanja životopisa člana zajednice sreo jednog člana koji se vrlo cenio zajednicu, on je uz moju pomoć uspešno našao praktični rad, i svi mogu da vide, pitanja planiranja karijere, pisanja životopisa, pripreme za jesenji regrutaciju, projekata koje je pominjao, svi mogu da nađu odgovore u zajednici.

Transakcije
25.🌟Kako razumijete Spring transakcije?
Spring obezbeđuje dva načina upravljanja transakcijama, programsko upravljanje transakcijama i deklarativno upravljanje transakcijama. Programsko upravljanje transakcijama znači da moramo ručno da pozivamo početak, potvrdu, poništenje transakcije, iako je fleksibilno ali kod je komplikovaniji. Deklarativno upravljanje transakcijama samo treba dodati @Transactional anotaciju na metodu koja treba transakciju, Spring će nam automatski da procesuira ce životni ciklus transakcije.

----ovaj deo ne morate da učite napamet, radi razumevanja početak----
Programsko upravljanje transakcijama može da se koristi TransactionTemplate i PlatformTransactionManager da realizuje, dozvoljava nam da direktno kontrolišemo granice transakcije u kodu.
public class AccountService {
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void transfer(final String out, final String in, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// Prebacivanje
accountDao.outMoney(out, money);
// Primanje
accountDao.inMoney(in, money);
}
});
}
}----ovaj deo ne morate da učite napamet, radi razumevanja kraj----
Osnovna implementacija Spring transakcije je kompletirana kroz AOP. Kada dodamo @Transactional anotaciju na metodu, Spring će kreirati proxy objekat za ovaj Bean, pre izvršavanja metode otvoriti transakciju, kada metoda normalno vrati potvrditi transakciju, ako metoda baci izuzetak poništiti transakciju.
Prednost deklarativne transakcije je da ne treba da mešamo kod upravljanja transakcijom u kod poslovne logike, mana je, najfinija granularnost je samo na nivou metode, ne može do nivoa bloka koda.
@Service
public class AccountService {
@Autowired
private AccountDao accountDao;
@Transactional
public void transfer(String out, String in, Double money) {
// Prebacivanje
accountDao.outMoney(out, money);
// Primanje
accountDao.inMoney(in, money);
}
}
- Java intervju vodič (plaćeni) sadrži originalno pitanje JD učesnika 10 pozadinska praktična prvi intervju: kako je Spring transakcija implementirana
- Java intervju vodič (plaćeni) sadrži originalno pitanje Agricultural Bank iskustva učesnika 7 Java pozadinski intervju: kako Spring garantuje transakciju
- Java intervju vodič (plaćeni) sadrži originalno pitanje BYD iskustva učesnika 12 Java tehnički intervju: da li ste koristili Spring transakciju, kako se koristi u projektu
- Java intervju vodič (plaćeni) sadrži originalno pitanje Shopee iskustva učesnika 13 prvi intervju: spring transakcija
- Java intervju vodič (plaćeni) sadrži originalno pitanje Alibaba Cloud iskustva učesnika 22 iskustvo: kako koristiti spring da realizujete transakciju
memo: 11. jula 2025. izmenjeno do ovde, danas član zajednice u VIP grupi rekao, Redis, MySQL, JVM delovi "Intervju pobeda" su vrlo jaki; drugi član je takođe nastavio da govori da je prošao nekoliko intervjua i sve je prošao.😄

26.Da li znate princip implementacije deklarativne transakcije?
Spring deklarativno upravljanje transakcijom je realizovano kroz AOP i proxy mehanizam, grubo može da se podeli u dve faze.
Prva faza se dešava pri pokretanju Spring kontejnera, on će da skenira sve Bean-ove. Ako otkrije da je na metodi nekog Bean-a označena @Transactional anotacija, Spring neće direktno da vrati ovu originalnu Bean instancu. Već će za ovaj Bean kreirati proxy objekat. Ovaj proxy objekat ima potpuno iste metode kao originalni objekat, ali unutra je neprocenjivo umotao logiku procesiranja transakcije.

Druga faza se dešava u fazi izvršavanja poziva metode, kada naš kod poziva onu metodu koja je modifikovana @Transactional anotacijom, zapravo se poziva metoda proxy objekta koji je Spring kreirao.

Transakcioni interceptor će pre nego što proxy objekat izvrši pravu poslovnu logiku, na osnovu konfiguracije @Transactional anotacije da dobavi atribute transakcije, na primer ponašanje propagacije, nivo izolacije itd., zatim kroz menadžer transakcije da otvori novu transakciju. I iz bazena konekcija baze podataka dobavlja konekciju, gasi njeno automatsko potvrđivanje.
public class TransactionInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// Dobavi atribute transakcije
TransactionAttribute txAttr = getTransactionAttribute(invocation.getMethod(), invocation.getThis().getClass());
// Počni transakciju
TransactionStatus status = transactionManager.getTransaction(txAttr);
try {
// Izvrši ciljnu metodu
Object retVal = invocation.proceed();
// Potvrdi transakciju
transactionManager.commit(status);
return retVal;
} catch (Throwable ex) {
// Poništi transakciju
transactionManager.rollback(status);
throw ex;
}
}
}Zatim, proxy objekat će pozvati pravu poslovnu metodu u originalnoj Bean instanci, ako poslovna metoda uspešno završi izvršavanje, ne bacajući nikakav izuzetak, onda će interceptor kroz menadžer transakcije potvrditi transakciju, trajno sačuvati sve prethodne operacije baze podataka.
Ako poslovna metoda baci izuzetak, interceptor će uhvatiti ovaj izuzetak, i kroz menadžer transakcije poništiti transakciju, opozvati sve prethodne operacije baze podataka.
Konačno, bez obzira da li je transakcija potvrđena ili poništena, interceptor će osloboditi konekciju baze podataka.
- Java intervju vodič (plaćeni) sadrži originalno pitanje JD učesnika 10 pozadinska praktična prvi intervju: kako je Spring transakcija implementirana
memo: 15. jula 2025. izmenjeno do ovde, danas prilikom uređivanja životopisa člana, video sam da je član rekao da je nakon izmene životopisa dobio praktičnu priliku za internu preporuku Star Ring Technology, i naučio mnogo, i iskreno zahvalio pomoći Java intervjua za pitanja za intervju. Zaista, videti najiskrenije povratne informacije svih, vratio sam se srećan.

27.U kojim slučajevima će @Transactional prestati da važi?
Iako je @Transactional veoma pogodan za korišćenje, zaista ima neke “ zamke “, ako se ne koristi ispravno može dovesti do prestanka važenja transakcije. Prema mom razumevanju i praksi, uglavnom postoji nekoliko uobičajenih situacija:
Prva, @Transactional anotacija se koristi na metodi koja nije modifikovana kao public.
AOP proxy mehanizam Spring-a određuje da ne može da proxy privatne metode. Zato što su privatne metode nevidljive u podklasi, proxy klasa ne može da je preklopi. Stoga, dodavanje @Transactional anotacije na privatnu metodu je potpuno nevažeće. Isto tako, treba izbegavati korišćenje metoda zaštićenih i podrazumevanih dozvola.
protected TransactionAttribute computeTransactionAttribute(Method method,
Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
}Druga, interni poziv metode, ovo je takođe najlakše zanemariti situaciju prestanka važenja. Ako u metodi A jedne klase, direktno pozovete drugu metodu B ove klase koja ima dodatu @Transactional anotaciju, onda transakcija metode B neće važiti.
Zato što kada metoda A poziva metodu B, koristi se this referenca, direktno se pristupa metodi originalnog objekta, zaobilazi se proxy objekat Spring-a, i dovodi do toga da logika transakcije u proxy objektu nema priliku da se izvrši.
public class UserService {
@Transactional
public void createUser(User user) {
// Direktno poziva drugu metodu ove klase, transakcija neće važiti
saveUser(user);
}
private void saveUser(User user) {
// Logika čuvanja korisnika
}
}Rešenje je da trenutnu klasu ubacite kao Bean u samu sebe, zatim pozovete metodu B kroz ovaj ubačeni Bean.

Treća, ako unutar metode transakcije koristite try-catch da uhvatite izuzetak, ali u catch bloku ne bacate izuzetak ponovo ili bacate novi izuzetak koji može da pokrene poništenje, onda interceptor transakcije Spring-a ne može da oseti pojavu izuzetka, i ne može da poništi.
@Transactional
public void process() {
try {
// Poslovna logika
} catch (Exception e) {
// Uhvaćen izuzetak ali nije ponovo bačen
// Transakcija neće biti poništena
}
}Četvrta, Spring transakcija podrazumevano samo poništava izuzetke tipa RuntimeException i Error. Ako u kodu bacite Checked Exception, koji je podklasa Exception ali ne podklasa RuntimeException, i niste naveli @Transactional(rollbackFor = Exception.class) da navedete tip izuzetka poništenja transakcije, onda transakcija takođe neće biti poništena.
@Transactional
public void process() throws Exception {
// Baca Checked Exception
throw new SQLException("This is a checked exception");
}
- Java intervju vodič (plaćeni) sadrži originalno pitanje Xiaomi jesenja regrutacija učesnika K prvi intervju: propagacija transakcije, da li će zaštićene i privatne metode transakcija važiti, koje su situacije kada ne važi
memo: 16. jula 2025. izmenjeno do ovde, danas prilikom uređivanja životopisa člana, video sam člana Oceanskog univerziteta Kine, master Univerziteta Sečuan, vrlo izvanredan, u osnovi iskustvo na kampusu i nagrade su popunjenje. Mogu da pomognem toliko izvanrednim članovima, takođe sam vrlo srećan.

28.Kako biste opšli nivoe izolacije Spring transakcija?
Nivo izolacije transakcije definiše nivo do kojeg jedna transakcija može biti pogođena drugim istovremenim transakcijama. SQL standard definira četiri nivoa izolacije, Spring ih podržava sve, definisane su u interfejsu TransactionDefinition.

Spring definiše pet nivoa izolacije na osnovu standardnih nivoa izolacije:
Gde DEFAULT znači koristiti podrazumevani nivo izolacije podložne baze podataka. Na primer za MySQL, podrazumevani nivo izolacije je ponovljivo čitanje, onda koristimo ponovljivo čitanje; za Oracle, podrazumevano je čitanje potvrđenog, onda koristimo čitanje potvrđenog. U stvarnim projektima, obično koristimo DEFAULT, neka baza podataka sama odluči o odgovarajućem nivou izolacije.
Čitanje nepotvrđenog je najniži nivo izolacije, dozvoljava čitanje nepotvrđenih podataka. Ovaj nivo će imati problem prljavog čitanja, to jest jedna transakcija može da pročita podatke koje druga transakcija još nije potvrdila. Na primer A transakcija modifikuje jedan podatak ali još nije potvrdila, B transakcija može da pročita ovu modifikovanu vrednost, ako A transakcija kasnije poništi, B transakcija je pročitala prljave podatke. Ovaj nivo se u stvarnim projektima praktično ne koristi, jer se ne može garantovati konzistentnost podataka.
Čitanje potvrđenog rešava problem prljavog čitanja, ali će se pojaviti problem neponovljivog čitanja, to jest u istoj transakciji više puta čitate isti podatak, možete dobiti različite rezultate. Na primer A transakcija prvo pročita jedan podatak, zatim B transakcija modifikuje i potvrdi ovaj podatak, A transakcija ponovo čita i otkriće da se podatak promenio.
Ponovljivo čitanje garantuje da je rezultat višestrukog čitanja istog podatka u istoj transakciji konzistentan, rešava problem neponovljivog čitanja. Ali će se pojaviti problem fantomskog čitanja, to jest u istoj transakciji više puta izvršavate isti upit, možete videti različiti broj zapisa. Na primer A transakcija upituje broj zapisa određenog uslova je 10, zatim B transakcija ubaci jedan zapis koji zadovoljava uslov i potvrdi, A transakcija ponovo upituje možda će videti 11 zapisa. InnoDB pogon skladištenja MySQL-a kroz ključne brave u velikoj meri rešava problem fantomskog čitanja.
Serijalizacija je najviši nivo izolacije, potpuno serijalizuje izvršavanje transakcija, može rešiti sve probleke istovremenosti, uključujući prljavo čitanje, neponovljivo čitanje i fantomsko čitanje. Ali performanse su najlošije, jer transakcije u osnovi izvršavaju u redu. U stvarnim projektima se retko koristi, osim ako ima ekstremno visoke zahteve za konzistentnošću podataka.
U Spring-u podesiti nivo izolacije je vrlo jednostavno, može se navesti kroz isolation atribut u @Transactional anotaciji.
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void someMethod() {
// Poslovna logika
}Ipak u stvarnim projektima, retko ručno podesavamo nivo izolacije, obično koristimo podrazumevani nivo baze podataka, samo kada naiđemo na specifične probleme istovremenosti razmatramo prilagođavanje.
- Java intervju vodič (plaćeni) sadrži originalno pitanje Huawei iskustva učesnika 8 tehnički drugi intervju: nivoi izolacije transakcija u Spring-u, ponašanje propagacije transakcija?
- Java intervju vodič (plaćeni) sadrži originalno pitanje Xiaomi iskustva učesnika E drugi odeljenje Java pozadinski tehnološki prvi intervju: mehanizam izolacije spring-a, koja je podrazumevana
memo: 13. jula 2025. izmenjeno do ovde, danas prilikom pomoći članu da uredi životopis, sreo sam člana master University of Electronic Science and Technology of China, bachelor Huazhong University of Science and Technology, on je rekao, on takođe preporučuje zajednicu mlađim kolegama, stvarno sam vrlo zadovoljan, mogu da imam takav ugled, vrlo sam pogođen, moram zahvaliti članovima na podršci.

29.🌟Kako biste opisali mehanizam propagacije transakcija Spring-a?
Jednostavno rečeno, kada metoda transakcije A poziva drugu metodu transakcije B, kako bi trebalo da radi transakcija metode B? Da li se pridružuje postojećoj transakciji metode A, ili otvara novu transakciju, ili radi na netransakcijski način? Ovo je problem koji mehanizam propagacije transakcije treba da reši.
Spring definiše sedam vrsta ponašanja propagacije transakcije, gde je REQUIRED podrazumevano ponašanje propagacije, znači ako trenutno postoji transakcija, pridruži se toj transakciji; ako trenutno nema transakcije, kreira novu transakciju.

Na primer u projektu Tech Pai stvarna praksa, operacija korisnika otključavanja plaćenog članka, uključuje kreiranje plaćanja narudžbe, ažuriranje statusa narudžbe i nekoliko drugih operacija baze podataka.

Te različite operacijske metode mogu da se stave u metodu sa @Transactional anotacijom, one su automatski u istoj transakciji, ili uspeju zajedno, ili ne uspeju zajedno.
Naravno, postoje i neke specifične situacije. Na primer, želimo da zabeležimo neke operacione dnevnike, ali ne želimo da neuspeh glavnog posla dovodi do poništenja dnevnika. U ovom trenutku REQUIRES_NEW je koristan. Bez obzira da li trenutno postoji transakcija ili ne, ponovo otvara potpuno novu, nezavisnu transakciju za izvršavanje. Tako, transakcija čuvanja dnevnika i transakcija glavnog posla se ne mešaju, čak i ako glavni poslo ne uspe i bude poništen, dnevnik može sigurno da se sačuva.
Dodatno, postoje i SUPPORTS, NOT_SUPPORTED i slične. SUPPORTS je prilično zen, ako ima transakcije koristi, ako nema ne koristi, pogodno za neke manje važne operacije ažuriranja. Dok je NOT_SUPPORTED odlučniji, on će suspendovati trenutnu transakciju, izvršava na netransakcijski način. Na primer ako u našoj transakciji treba pozvati treće lice, sporo reagujući interfejs, ako ovaj poziv uključujemo u transakciju, dugo će zauzeti konekciju baze podataka. Ako ga obuhvatimo sa NOT_SUPPORTED, možemo izbeći ovaj problem.
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void callExternalApi() {
// Pozovi interfejs treće strane
}Konačno, postoji i jedan prilično specifičan NESTED, ugnježdena transakcija. On je malo kao REQUIRES_NEW, ali nije potpuno isti. NESTED je podtransakcija roditeljske transakcije, ako se roditeljska transakcija poništi, on sigurno mora biti poništen. Ali ako se sam poništi, neće uticati na roditeljsku transakciju. Ova karakteristika je posebno korisna pri procesiranju nekih grupnih operacija, kada želimo delimično poništenje. Ali zahteva da baza podataka podržava funkciju Savepoint, MySQL podržava.
Da li se transakcija može propagirati u novoj niti?
Mehanizam propagacije transakcije je realizovan kroz ThreadLocal, stoga, ako se pozvana metoda nalazi u novoj niti, propagacija transakcije će prestati da važi.
@Transactional
public void parentMethod() {
new Thread(() -> childMethod()).start();
}
public void childMethod() {
// Operacije ovde neće biti izvršene u okviru transakcije parentMethod
}Da li će transakcija važiti za zaštićene i privatne metode?
Moje razumevanje je: dodavanje transakcije na privatnu metodu sigurno neće važiti, dok će zaštićena metoda u specifičnom proxy režimu možda važiti, ali ova dva načina korišćenja treba izbegavati, nisu preporučeni načini korišćenja.
Iza toga stoji proxy mehanizam Spring AOP-a.
Prvo ću da pričam o JDK dinamičkom proxy-ju, on zahteva da ciljna klasa mora implementirati jedan ili više interfejsa. To znači da proxy može samo da presreće metode deklarisane u interfejsu, dok se zaštićene i privatne metode ne mogu deklarisati u interfejsu, stoga u JDK dinamičkom proxy-ju, anotacije transakcije ovih metoda će se direktno ignorisati.
A posle Spring Boot 2.0, Spring AOP podrazumevano koristi CGLIB proxy. CGLIB proxy kroz nasleđivanje ciljne klase kreira proxy objekat.
Za privatne metode, pošto ne mogu biti preklopljene u podklasi, CGLIB proxy takođe ne može da ih presreće, transakcija ne može da važi. Za zaštićene metode, pošto mogu biti preklopljene u podklasi, teoretski transakcija važi.
----ovaj deo ne morate da učite napamet, radi razumevanja početak----
Kreiramo zaštićenu metodu pod nazivom protectedTransactionalMethod, ona je označena @Transactional anotacijom. Ova metoda će prvo ubaciti jedan zapis u bazu podataka (TestEntity instancu). Odmah zatim, ona će baciti RuntimeException.

- Ako transakcija važi: kada se RuntimeException baci, menadžer transakcija Spring-a će ga uhvatiti i pokrenuti poništenje transakcije. To znači, prethodno ubačeni zapis u bazu podataka će biti poništen. Konačno, u bazi podataka neće ostati ovaj zapis.
- Ako transakcija ne važi: čak i ako je RuntimeException bačen, pošto nema upravljanja transakcijom, već izvršena operacija ubacivanja u bazu podataka neće biti poništena. Konačno, u bazi podataka će ostati ovaj zapis.
Kreirali smo javnu metodu testProtectedTransaction, ona kroz this.protectedTransactionalMethod() način direktno poziva tu zaštićenu metodu. Zatim pristupamo /api/v1/test/transaction/protected da pokrenemo ovaj poziv.
Rezultat: u bazi podataka će ostati zapis pod nazivom 'test-protected'. Ovo dokazuje da je zbog internog poziva, zaobišao Spring AOP proxy, @Transactional anotacija nije važila.
Kreirali smo drugu javnu metodu testProtectedTransactionWithSelfProxy. U ovoj metodi, kroz “sam-ubačeni” proxy objekat self pozivamo self.protectedTransactionalMethod(). Zatim pristupamo /api/v1/test/transaction/protected/proxy da pokrenemo ovaj poziv.
Rezultat: u bazi podataka neće ostati zapis pod nazivom 'test-protected-proxy'. Ovo dokazuje da kroz poziv proxy objekta, Spring AOP uspešno presreće i otvara transakciju, konačno kada se desi izuzetak pravilno poništava transakciju.

----ovaj deo ne morate da učite napamet, radi razumevanja kraj----
- Java intervju vodič (plaćeni) sadrži originalno pitanje JD učesnika 10 pozadinska praktična prvi intervju: mehanizam propagacije transakcija
- Java intervju vodič (plaćeni) sadrži originalno pitanje Xiaomi jesenja regrutacija učesnika K prvi intervju: propagacija transakcije, da li će zaštićene i privatne metode transakcija važiti, koje su situacije kada ne važi
- Java intervju vodič (plaćeni) sadrži originalno pitanje Huawei iskustva učesnika 8 tehnički drugi intervju: nivoi izolacije transakcija u Spring-u, ponašanje propagacije transakcija?
- Java intervju vodič (plaćeni) sadrži originalno pitanje OPPO iskustva učesnika 8 pozadinski razvoj jesenja regrutacija prvi intervju: pričajte mehanizam propagacije transakcija Spring
- Java intervju vodič (plaćeni) sadrži originalno pitanje Alibaba Cloud iskustva učesnika 22 iskustvo: predstavi model propagacije transakcija
memo: 14. jula 2025. izmenjeno do ovde, danas prilikom pomoći članu da uredi životopis, član master Zhejiang University nije samo dobio praktičnu ponudu Tencent WXG, jesenja regrutacija je takođe počela simultano, mogu samo da kažem da izvanredni članovi zaista ne čekaju kasno!

MVC
30.Koje su ključne komponente Spring MVC-a?
Spring MVC kao ključni modul za procesiranje Web zahteva u Spring framework-u, njegov dizajn sledi klasični MVC model, prema mom razumevanju, njegove ključne komponente uglavnom uključuju:
Front kontroler DispatcherServlet, ovo je ulaz i ključni dispečer Spring MVC-a. Kada HTTP zahtev stigne na server, prvo ga prima DispatcherServlet. On je odgovoran za distribuciju zahteva na odgovarajući procesor, to jest metodu u Controller-u, i koordinira rad drugih komponenata.

U Spring Boot projektu, pokretanje DispatcherServlet-a je završeno kroz automatsku konfiguraciju. Spring Boot će automatski registrovati podrazumevani DispatcherServlet, i mapirati ga na /.
@Bean
public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet, "/"); // Podrazumevana mapa putanja je "/"
registration.setName("dispatcherServlet");
return registration;
}Mapiranje procesora HandlerMapping, kada zahtev uđe, front kontroler će pitati mapiranje procesora: “ovaj URL bi trebao da procesira koja metoda kojeg Controller-a?” Zatim će na osnovu @RequestMapping, @GetMapping ovih anotacija da upari zahtev.

Procesor Handler, zapravo je metoda Controller-a koju mi napišemo, ovo je mesto gde se stvarno procesira poslovna logika.
Adapter procesora HandlerAdapter, odgovoran je za pozivanje metode procesora, i procesira vezivanje parametara, konverziju tipova itd. Zato što procesori mogu imati različite tipove, na primer način anotacije, način implementacije interfejsa itd., adapter procesora je da ujedini način poziva.
Rezolver prikaza ViewResolver, nakon završetka procesiranja poslovne logike, ako treba renderovati prikaz, ViewResolver će na osnovu vraćenog naziva prikaza razložiti stvarni objekat prikaza, na primer Thymeleaf. U projektima razdvojenog prednjeg i zadnjeg dela, ova komponenta se više koristi za vraćanje JSON podataka.

Rezolver izuzetaka HandlerExceptionResolver, hvata i procesira izuzetke bačene tokom procesiranja zahteva. Obično, možemo kroz @ControllerAdvice i @ExceptionHandler da definišemo logiku procesiranja izuzetaka, osigurujemo vraćanje prijateljskog odgovora o grešci.

Pored toga, postoji i rezolver otpremanja datoteka MultipartResolver, koristi se za procesiranje zahteva otpremanja datoteka; interceptor HandlerInterceptor, koristi se za izvršavanje neke dodatne logike pre i posle procesiranja zahteva, na primer provera autorizacije, evidencija dnevnika itd.
memo: 17. jula 2025. izmenjeno do ovde, juče član je rekao da je napisao Redis projekat od nule, koristeći Go jezik, danas sam išao da vidim dokumentaciju i kod, vrlo dobro napisano, komentari koda su veoma jasni, dokumentacija je vrlo detaljna, može se videti trud člana. Pisanje složenih sistema od nule vrlo testira sposobnost čoveka, vidim da je funkcija koju je realizovao: tipovi podataka stringa i heš, RES parser protokola, korišćenje goroutine-a za simultano procesiranje više konekcija, AOF protokol perzistencije itd., vrlo jako.

31.🌟Da li znate tok rada Spring MVC-a?
Jednostavno rečeno, Spring MVC je framework za procesiranje zahteva zasnovan na Servlet-u, ključni tok može biti sažet: prijem zahteva → distribucija rute → procesiranje kontrolera → rezolucija prikaza.



HTTP zahtev koji iniciraju korisnici, prvo će biti uhvaćen od strane DispatcherServlet-a, ovo je “front kontroler” Spring MVC-a, odgovoran je za presretanje svih zahteva, igra ulogu jedinstvenog ulaza.
Nakon što DispatcherServlet primi zahtev, prema URL-u, metodi zahteva i drugim informacijama, prepusta HandlerMapping-u da upari rutu, pronađe odgovarajući procesor, to jest specifičnu metodu u Controller-u.

Nakon pronalaska odgovarajuće metode Controller-a, DispatcherServlet će poveriti adapteru procesora HandlerAdapter da pozove. Adapter procesora je odgovoran za izvršavanje same metode, i procesira vezivanje parametara, konverziju tipova podataka itd. U razvoju vođenom anotacijama, često se koristi RequestMappingHandlerAdapter. Ovaj sloj će automatski ubaciti parametre zahteva u parametre metode, i pozvati Controller da izvrši stvarnu poslovnu logiku.

Metoda Controller-a konačno će vratiti rezultat, na primer naziv prikaza, ModelAndView ili direktno JSON podatke.
Kada metoda Controller-a vrati naziv prikaza, DispatcherServlet će pozvati ViewResolver da ga razloži kao stvarni objekat View, na primer Thymeleaf stranicu. U projektima razdvojenog prednjeg i zadnjeg dela, ovaj korak je obično vraćanje JSON podataka.
Konačno, objekat View završava renderovanje, ili direktno kroz DispatcherServlet vraća JSON rezultat klijentu.
Zašto je još potreban HandlerAdapter?
Spring MVC podržava više stilova procesora, na primer procesore bazirane na @Controller anotaciji, procesore koji implementiraju Controller interfejs itd. Ako nema adaptera procesora, DispatcherServlet bi morao hardkodirati način poziva svakog procesora, framework bi postao vrlo krut — dodavanje novog tipa Controller-a, mora promeniti kod DispatcherServlet-a.
Stoga, Spring uvodi HandlerAdapter kao adapter, sklanja razlike između različitih kontrolera, daje DispatcherServlet-u jedinstven ulaz za poziv.
Na primer, ako je procesor koji implementira Controller interfejs, DispatcherServlet će koristiti SimpleControllerHandlerAdapter da ga adaptira.
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
// ... izostavljena jedna nevažna metoda ...
}Ako se koristi procesor sa @RequestMapping anotacijom, DispatcherServlet će koristiti RequestMappingHandlerAdapter da ga adaptira.
public class RequestMappingHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof HandlerMethod);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// Izvrši metodu i vrati ModelAndView
return invokeHandlerMethod(handlerMethod, request, response);
}
}
- Java intervju vodič (plaćeni) sadrži originalno pitanje Tencent Java pozadinski praktični prvi intervju: pričajte ceo proces procesiranja od prednjeg zahteva do SpringMVC-a.
- Java intervju vodič (plaćeni) sadrži originalno pitanje državnog preduzeća intervju: pričajte tok SpringMVC-a
- Java intervju vodič (plaćeni) sadrži originalno pitanje male kompanije iskustva učesnika 5 Java pozadinski intervju: tok rada springMVC ja sam otprilike odgovorio kako je u Intervju pobedi, na polovine me prekinu: onda će biti Handler, šta je taj Handler. Prethodni Handler već zna controller, zar ne mogu direktno da izvršim, zašto treba Adapter.
- Java intervju vodič (plaćeni) sadrži originalno pitanje JD iskustva učesnika 8 intervju: SpringMVC framework
- Java intervju vodič (plaćeni) sadrži originalno pitanje ByteDance učesnika 17 pozadinski tehnološki intervju: izvršni tok springmvc-a
memo: 18. jula 2025. izmenjeno do ovde, danas prilikom pomoći članu da uredi životopis, sreo sam člana čije su nagrade i priznanja gotovo popunjene, nacionalna stipendija za nadarene studente, pokrajinska takmičenja,.studentske "dobre studente" itd., ovde takođe toplom napominjem svima, ako imate sposobnost i imate vreme za borbu za školske nagrade i priznanja, ipak se potrudite da ih osvojite, posebno kada tražite posao u centralnim državnim preduzećima, vrlo će biti korisno.

32.Kakav je tok interfejsa u Restful stilu SpringMVC-a?
U tradicionalnom MVC-u, metoda Controller-a obično vraća naziv prikaza ili ModelAndView objekat, zatim rezolver prikaza ViewResolver razrešava i renderira u HTML stranicu. Ali u RESTful arhitekturi, obično se vraća JSON ili XML, više nije kompletna stranica.
Dve veoma važne anotacije: @RestController je ekvivalent @Controller i @ResponseBody kombinacije. Kada se koristi @RestController na klasi, ona će reći Spring-u da se povratne vrednosti svih metoda u ovoj klasi trebaju direktno upisati u HTTP telo odgovora, i više neće biti razrešene kao prikaz.
@ResponseBody se može koristiti na nivou metode, isto deluje. On označava da će se povratna vrednost ove metode koristiti kao sadržaj tela odgovora, Spring će preskočiti korak razrešavanja prikaza.
HttpMessageConverter je ključ za realizaciju RESTful stila. Kada Spring detektuje @ResponseBody anotaciju, on će koristiti HttpMessageConverter da serializuje Java objekat koji vraća metoda Controller-a u navedeni format, kao JSON.
Podrazumevano, ako na classpath-u postoji Jackson biblioteka, Spring Boot će automatski konfigurisati MappingJackson2HttpMessageConverter da procesira konverziju JSON-a. Odgovarajuće, za parametre metoda sa @RequestBody anotacijom, takođe će koristiti ovaj konverter da deserijalizuje JSON podatke iz tela zahteva u Java objekat.

Dakle, tok interfejsa RESTful može biti sažet: zahtev stiže do front kontrolera DispatcherServlet → kroz HandlerMapping pronađe odgovarajuću metodu Controller-a → izvrši metodu i vrati podatke → koristi HttpMessageConverter da konvertuje podatke u JSON ili XML format → direktno upiše u HTTP telo odgovora.

Sažetosti, tok interfejsa RESTful kroz @RestController i HttpMessageConverter “skraćuje put”, izostupljuje proces renderovanja ViewResolver i View, direktno konvertuje podatke u navedeni format i vraća, vrlo je pogodno za scenarije razdvojenog prednjeg i zadnjeg dela.
memo: 19. jula 2025. izmenjeno do ovde, danas član mi je poslao privatnu poruku da je dobio praktičnu ponudu JD, kako se treba pripremiti za jesenju regrutaciju? Praktične ponude u julu zaista će biti manje, ali i dalje postoji jedan deo, ako u ovoj fazi i dalje želite da jurite za praktičnom radom, zaista možete pokupati ostatke.

Spring Boot
33.🌟Predstavite SpringBoot?
Spring Boot može biti veliki prekid u Spring ekosistemu, on je enormno pojednostavlio proces razvoja i implementacije Spring aplikacija.

Ranije smo koristeći Spring za razvoj projekata, morali smo da konfigurišemo gomilu XML datoteka, uključujući definiciju Bean-a, konfiguraciju izvora podataka, konfiguraciju transakcije itd., vrlo je komplikovano. Pored toga, morali smo ručno da upravljamo odnosima zavisnosti raznih jar paketa, lako se pojavljuju problemi konflikta verzija. Pri implementaciji smo morali zasebno da postavimo Tomcat server, ceo proces je vrlo komplikovan. Spring Boot je rođen da reši ove probleme.
“Dogovor je važniji od konfiguracije” je ključna filozofija Spring Boot-a. On je unapred podesio mnogo podrazumevanih konfiguracija, na primer podrazumevano koristi ugrađeni Tomcat server, podrazumevani framework za evidencije je Logback itd. Na ovaj način, mi programeri treba samo da fokusiramo na poslovnu logiku, ne moramo da se borimo sa raznim detaljima konfiguracije.
Automatska montaža je takođe velika karakteristika Spring Boot-a, ona će automatski konfigurisati odgovarajuće Bean-ove na osnovu zavisnosti uvedenih u projektu. Na primer, uveli smo Spring Data JPA, Spring Boot će automatski konfigurisati izvor podataka; na primer, uveli smo Spring Security, Spring Boot će automatski konfigurisati Bean-ove vezane za bezbednost.
Spring Boot takođe nudi mnogo funkcija spremnih za upotrebu, na primer Actuator monitoring, DevTools razvojni alat, Spring Boot Starter itd. Actuator nam omogućava lako monitoringiranje zdravlja aplikacije, pokazatelja performansi itd.; DevTools može ubrzati efikasnost razvoja, na primer automatsko restartovanje, vruća implementacija itd.; Spring Boot Starter su neke pre-konfigurisane kolekcije zavisnosti, nam omogućuju brzo uvođenje nekih često korišćenih funkcija.
Koje su često korišćene anotacije Spring Boot-a?
Anotacije Spring Boot-a su mnoge, izabram dve da pričam.
@SpringBootApplication: ovo je ključna anotacija Spring Boot-a, to je kombinovana anotacija, uključuje@Configuration,@EnableAutoConfigurationi@ComponentScan. Ona označava ulaz Spring Boot aplikacije.@SpringBootTest: anotacija za testiranje Spring Boot aplikacije, ona će učitati ceo Spring kontekst, pogodna za integritetno testiranje.
- Java intervju vodič (plaćeni) sadrži ovo pitanje iz Huawei OD iskustva: pričajte karakteristike Spring Boot-a.
- Java intervju vodič (plaćeni) sadrži originalno pitanje Baidu iskustva učesnika 1 Wenxin Yiyan 25 praktični Java pozadinski intervju: osnovni princip SpringBoot-a
- Java intervju vodič (plaćeni) sadrži originalno pitanje državnog preduzeća delimično iskustva učesnika 9 intervju: koje vrste konfiguracije Springboot zasnovane na Spring-u postoje
- Java intervju vodič (plaćeni) sadrži originalno pitanje Alibaba Cloud iskustva učesnika 22 iskustvo: često korišćene anotacije springboot-a
memo: 20. jula 2025. izmenjeno do ovde, danas član mi je poslao privatnu poruku da je kajao što se ranije nije pridružio zajednici, nakon pridruživanja zajednici, otkrio je da svi rano rukuju za svoju budućnost. Vrlo stvarno, dobro, ovo je vrednost zajednice, ulaznica od preko 100 juana može da pruži stvari koje vam nekoliko desetina hiljada školarine ne može da pruži.

34.🌟Da li znate princip automatske montaže Spring Boot-a?
U Spring Boot-u, anotacija za omogućavanje automatske montaže je @EnableAutoConfiguration. Ova anotacija će reći Spring-u da skenira sve dostupne automatske konfiguracijske klase.

Spring Boot radi dalje pojednostavljenja, ovu anotaciju uključio u @SpringBootApplication anotaciju. To jest, kada na glavnoj klasi koristimo @SpringBootApplication anotaciju, zapravo smo već omogućili automatsku montažu.
Kada se metoda main izvršava, Spring će ići u class path da potraži datoteku spring.factories, pročita listu automatski konfigurisanih klasa unutar. Na primer u našem projektu Tech Pai, u modulima paicoding-core i paicoding-service postoje spring.factories, registrovali su ForumCoreAutoConfig i ServiceAutoConfig, ove dve konfiguracijske klase će biti automatski učitane pri pokretanju projekta.

Zatim unutar svake automatske konfiguracijske klase, obično postoji @Configuration anotacija, istovremeno kombinovana sa raznim @Conditional anotacijama za kontrolu uslova. Kao Tech Pai RabbitMqAutoConfig klasa, koristi @ConditionalOnProperty anotaciju da pročita da li je u konfiguracionoj datoteci uključen rabbitmq.switchFlag, da odluči da li inicijalizuje RabbitMQ potrošačku nit.

Druga česta scena je automatsko ubacivanje Bean-a, na primer u Tech Pai ServiceAutoConfig koristi @ComponentScan da skenira service paket, @MapperScan skenira MyBatis mapper interfejs, realizuje automatsku montažu sloja poslovanja i DAO sloja.
Specifičan proces izvršavanja može biti sažet: Spring Boot projekt pri pokretanju učitava sve automatske konfiguracijske klase, zatim proverava jednu po jednu njihove uslove važenja, kada su uslovi zadovoljeni instancira i kreira odgovarajuće Bean-ove.

Vreme izvršavanja automatske montaže je pri pokretanju Spring kontejnera. Konkretno, procesira se u ConfigurationClassPostProcessor ovom BeanPostProcessor-u, on će razložiti @Configuration klase, uključujući automatske konfiguracijske klase uvedene kroz @Import.
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// Proveri da li je automatska konfiguracija omogućena. Ako uslovne anotacije kao @ConditionalOnClass čine automatsku konfiguraciju neprimenjivom za trenutnu okolinu, vrati praznu konfiguracionu stavku.
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// Dobavi atribute @EnableAutoConfiguration anotacije na startnoj klasi, ovo može uključiti isključenje specifičnih automatski konfigurisanih klasa.
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// Dobavi sve kandidatne automatski konfigurisane klase iz spring.factories. Ovo se realizuje učitavanjem odgovarajućih stavki u META-INF/spring.factories datoteci.
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// Ukloni duplikate iz liste konfiguracija, osiguraj da se svaka automatski konfigurisana klasa razmatra samo jednom.
configurations = removeDuplicates(configurations);
// Na osnovu atributa anotacije razreši koje automatske konfigurisane klase treba isključiti.
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// Proveri da li isključene klase postoje u kandidatnim konfiguracijama, ako postoje, baci izuzetak.
checkExcludedClasses(configurations, exclusions);
// Ukloni isključene klase iz kandidatnih konfiguracija.
configurations.removeAll(exclusions);
// Primeni filter da dalje filtrira automatske konfigurisane klase. Filter može biti baziran na uslovnim anotacijama kao @ConditionalOnBean itd. da isključi specifične konfiguracijske klase.
configurations = getConfigurationClassFilter().filter(configurations);
// Pokreni događaj uvoza automatske konfiguracije, dozvoli slušačima da intervenišu u proces automatske konfiguracije.
fireAutoConfigurationImportEvents(configurations, exclusions);
// Kreiraj i vrati AutoConfigurationEntry objekat koji sadrži konačno određene automatske konfigurisane klase i isključene konfiguracijske klase.
return new AutoConfigurationEntry(configurations, exclusions);
}
- Java intervju vodič (plaćeni) sadrži originalno pitanje Didi učesnika 2 tehnički drugi intervju: zašto SpringBoot pri pokretanju može da automatski montira
- Java intervju vodič (plaćeni) sadrži originalno pitanje Tencent iskustva učesnika 22 letnja praktična prvi intervju: kako Spring Boot čini da pri pokretanju ubaci neke bean-ove
- Java intervju vodič (plaćeni) sadrži originalno pitanje BYD iskustva učesnika 3 Java tehnički prvi intervju: pričajte princip automatske montaže Spring Boot-a
- Java intervju vodič (plaćeni) sadrži originalno pitanje Agricultural Bank učesnika 1 intervju: automatska montaža spring boot-a
- Java intervju vodič (plaćeni) sadrži originalno pitanje Baidu iskustva učesnika 1 Wenxin Yiyan 25 praktični Java pozadinski intervju: kako SpringBoot realizuje automatsku montažu
- Java intervju vodič (plaćeni) sadrži originalno pitanje OPPO iskustva učesnika 1 intervju: kako se realizuje automatska konfiguracija?
memo: 21. jula 2025. izmenjeno do ovde, danas član mi je poslao privatnu poruku da je dobio ponudu AsiaInfo Technology + Neolix bezvoznih vozila, kako da bira, ako bi ste bili vi, kako biste vi izabrali?

35.🌟Kako da kreirate sopstveni SpringBoot Starter?
Prvi korak, SpringBoot zvanično sugeriše da format imenovanja treće strane starter-a je xxx-spring-boot-starter, stoga možemo kreirati projekat pod nazivom my-spring-boot-starter, uključuje dva modula, jedan je autoconfigure modul, uključuje logiku automatske konfiguracije; jedan je starter modul, samo uključuje deklaraciju zavisnosti.
<properties>
<spring.boot.version>2.3.1.RELEASE</spring.boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>Drugi korak, kreirajte automatsku konfiguracijsku klasu, obično u paketu autoconfigure, uloga ove klase je da kreira i konfiguriše Bean-ove na osnovu svojstava u konfiguracionoj datoteci.
@Configuration
@EnableConfigurationProperties(MyStarterProperties.class)
public class MyServiceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyStarterProperties properties) {
return new MyService(properties.getMessage());
}
}Treći korak, kreirajte klasu svojstava konfiguracije, koristi se za čitanje svojstava iz konfiguracione datoteke. Obično koristi @ConfigurationProperties anotaciju da označi ovu klasu.
@ConfigurationProperties(prefix = "mystarter")
public class MyStarterProperties {
private String message = "Ergov Java napredni put je vrlo dobar!";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}Četvrti korak, kreirajte jednostavnu servisnu klasu, koristi se za pružanje poslovne logike.
public class MyService {
private final String message;
public MyService(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}Peti korak, u direktorijumu src/main/resources/META-INF kreirajte datoteku pod nazivom spring.factories, recite SpringBoot-u da pri pokretanju učitava našu automatsku konfiguracijsku klasu.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.itwanger.mystarter.autoconfigure.MyServiceAutoConfigurationŠesti korak, koristite Maven da spakujete ovaj projekat.
mvn clean installSedmi korak, u drugim Spring Boot projektima, kroz Maven dodajte ovu prilagođenu Starter zavisnost, i kroz application.properties konfigurišite informacije:
mystarter.message=javasi.devZatim možete u Spring Boot projektu ubaciti MyStarterProperties da ga koristite.

Pokrenite projekat, zatim u pretraživaču unesite localhost:8081/hello, možete videti da je vraćeni sadržaj javasi.dev, što pokazuje da je naš prilagođeni Starter uspešno radio.

Da li znate princip Spring Boot Starter-a?
Ključna ideja Starter-a je da pakuje povezane zavisnosti zajedno, programerima samo treba uvesti jednu starter zavisnost, mogu dobiti kompletnu funkcionalnu modul.
Kada u pom.xml uvedemo starter, Maven će automatski razložiti stablo zavisnosti ovog starter-a, preuzeti sve potrebne jar pakete.
Svaki starter će sadržati odgovarajuću automatsku konfiguracijsku klasu, ove konfiguracijske klase kroz uslovne anotacije da procene da li treba da važe. Na primer kada uvedemo spring-boot-starter-web, on će automatski konfigurisati Spring MVC, ugrađeni Tomcat server itd.
spring.factories datoteka je ključ automatske montaže Spring Boot-a, nalazi se u META-INF direktorijumu svakog starter-a. Ova datoteka navodi sve automatske konfiguracijske klase, Spring Boot pri pokretanju će čitati ovu datoteku, učitava odgovarajuće konfiguracijske klase.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.autoconfigure.DemoAutoConfiguration,\
com.example.demo.autoconfigure.AnotherAutoConfiguration
- Java intervju vodič (plaćeni) sadrži originalno pitanje ByteDance iskustva učesnika 1 Java pozadinski tehnološki prvi intervju: da li ste pakovali springboot starter?
- Java intervju vodič (plaćeni) sadrži originalno pitanje Tencent Cloud Smart iskustva učesnika 20 drugi intervju: da li znate princip Spring Boot Starter-a?
- Java intervju vodič (plaćeni) sadrži originalno pitanje Kuaishou učesnika 4 prvi intervju: zašto koristiti SpringBoot? Princip i proces automatske montaže SpringBoot-a? Koja je uloga @Import? Ako želite da SpringBoot automatski konfiguriše prilagođene jar pakete, šta treba da uradite?
memo: 22. jula 2025. izmenjeno do ovde, danas član u VIP grupi priča, otkrio sam da dve osobe rade u Xiaohongshu, veoma su srodne, oni koji mogu da idu na praktični rad u Xiaohongshu, jesenja regrutacija je u osnovi sigurna kao stari pas😄, praktični rad ovog jednoroga ima vrlo visoku vrednost.

36.🌟Da li znate princip pokretanja Spring Boot-a?
Pokretanje Spring Boot-a se uglavnom vrti oko dva ključna elementa, jedan je @SpringBootApplication anotacija, drugi je SpringApplication.run() metoda.

Prvo ću da pričam o @SpringBootApplication anotaciji, to je kombinovana anotacija, uključuje @SpringBootConfiguration, @EnableAutoConfiguration i @ComponentScan, uloge ove tri anotacije su redom:
@SpringBootConfiguration: označava da je ova klasa Spring Boot konfiguracijska klasa, ekvivalent Spring konfiguracionoj datoteci.@EnableAutoConfiguration: kaže Spring Boot-u da može vršiti automatsku konfiguraciju. Na primer, projekat uveo zavisnost Spring MVC-a, onda Spring Boot automatski konfiguriše DispatcherServlet, HandlerMapping i druge komponente.@ComponentScan: skenira komponente u trenutnom paketu i njegovim podpaketima, registruje kao Bean.

Dobro, zatim ću da pričam o SpringApplication.run() metodi, to je ulaz za pokretanje Spring Boot projekta, interni tok može grubo biti podeljen u 5 koraka:
①, kreirajte instancu SpringApplication, identifikujte tip aplikacije, na primer da li je standardni Servlet Web ili reaktivan WebFlux, zatim pripremite slušače i inicijalizujte kontejner slušalaca.
②, kreirajte i pripremite ApplicationContext, učitajte glavnu klasu kao izvor konfiguracije.
③, osvežite Spring kontekst, pokrenite instanciranje Bean-a, na primer skenirajte i registrujte Bean-ove na putanjama navedenim u @ComponentScan.
④, pokrenite automatsku konfiguraciju, u Spring Boot 2.7 i prethodno se učitava kroz spring.factories, u 3.x se čita kroz AutoConfiguration.imports, i kombinuje sa serijom @ConditionalOn anotacija da registruje Bean-ove na osnovu uslova.
⑤, ako su uvedene Web zavisnosti, kreiraće i pokrenuti Tomcat kontejner, završiti slušanje HTTP porta.
Ključna logika koda je sledeća:
public ConfigurableApplicationContext run(String... args) {
// 1. Kreirajte slušaoce pri pokretanju i pokrenite događaj pokretanja
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
// 2. Pripremite okruženje za izvršavanje
ConfigurableEnvironment environment = prepareEnvironment(listeners);
configureIgnoreBeanInfo(environment);
// 3. Kreirajte kontekst
ConfigurableApplicationContext context = createApplicationContext();
try {
// 4. Pripremite kontekst
prepareContext(context, environment, listeners, args);
// 5. Osvežite kontekst, završite inicijalizaciju i montažu Bean-a
refreshContext(context);
// 6. Pozovite pokretače
afterRefresh(context, args);
// 7. Pokrenite događaj završetka pokretanja
listeners.started(context);
} catch (Exception ex) {
handleRunFailure(context, ex, listeners);
}
return context;
}Kako da dodate sopstvenu logiku u fazi pokretanja?
Može se kroz implementaciju ApplicationRunner interfejsa završiti sopstvenu logiku nakon pokretanja.
Na primer u projektu Tech Pai, mi u metodi run dodajemo: konfiguraciju konverzije JSON tipa i dinamičko podešavanje adrese pristupa aplikaciji itd.

Zašto Spring Boot pri pokretanju može da pronađe @SpringBootApplication anotaciju na main metodi?
Zapravo Spring Boot sam ne pronalazi @SpringBootApplication anotaciju, već mi kroz program kažemo tome.
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}Mi Application.class prosleđujemo kao parametar metodi run. Ova Application klasa je označena @SpringBootApplication anotacijom, koristi se da kaže Spring Boot-u: molim te koristi ovu klasu kao konfiguracijsku klasu za pokretanje.
Zatim, SpringApplication pri vreme izvršavanja će registrovati ovu klasu u Spring kontejneru.
Koja je podrazumevana putanja skeniranja paketa Spring Boot-a?
Podrazumevana putanja skeniranja paketa Spring Boot-a je paket u kojoj se nalazi glavna klasa i njegovi podpaketi.
Na primer u projektu stvarne prakse Tech Pai, startna klasa QuickForumApplication se nalazi u paketu com.github.paicoding.forum.web, onda Spring Boot podrazumevano će skenirati paket com.github.paicoding.forum.web i sve komponente u njegovim podpaketima.

- Java intervju vodič (plaćeni) sadrži originalno pitanje Didi učesnika 2 tehnički drugi intervju: zašto Spring Boot pri pokretanju može da pronađe anotaciju iznad Main klase
- Java intervju vodič (plaćeni) sadrži originalno pitanje Tencent iskustva učesnika 22 letnja praktična prvi intervju: podrazumevana putanja skeniranja paketa Spring Boot-a?
- Java intervju vodič (plaćeni) sadrži originalno pitanje WeBank učesnika 1 Java pozadinski prvi intervju: da li poznate @SpringBootApplication anotaciju?
- Java intervju vodič (plaćeni) sadrži originalno pitanje državnog preduzeća delimično iskustva učesnika 9 intervju: radni princip Springboot-a?
- Java intervju vodič (plaćeni) sadrži originalno pitanje JD iskustva učesnika 5 Java pozadinski tehnološki prvi intervju: proces pokretanja SpringBoot (zaboravio)
- Java intervju vodič (plaćeni) sadrži originalno pitanje Bilibili učesnika 1 drugi intervju: mehanizam pokretanja springBoot-a, koji se koraci dešavaju nakon pokretanja
memo: 10. avgusta 2025. izmenjeno do ovde, danas prilikom uređivanja životopisa člana, vrlo sam pogođen, jer je član rekao, on je mnogim oko sebe preporučio Ergov programerski zajednicu, i povratne informacije su vrlo dobre. Stvarno zahvalan, reputacija članova, bez svih, zaista ne bi mogao da stignem do sada.

37.Pričajte razliku između SpringBoot-a i SpringMVC-a? (dopuna)
- aprila 2024. dodatak
SpringMVC je modul Spring-a, specijalizovan za Web razvoj, procesira HTTP zahtev i odgovor. Dok je cilj Spring Boot-a da pojednostavi proces razvoja Spring aplikacije, može brzo integrisati SpringMVC kroz starter način.
Tradicionalni Web projekti obično treba ručno da konfigurišu mnoge stvari, na primer DispatcherServlet, ViewResolver, HandlerMapping itd. Dok Spring Boot kroz automatsku montažu nama pomaže da izbegnemo ove zamorne konfiguracije.
Spring Boot takođe ima ugrađeni ugrađeni Servlet kontejner, na primer Tomcat, tako nam ne treba kao tradicionalni Web projekti da konfigurišemo Tomcat kontejner, zatim izvezemo war paket da pokrenemo. Samo treba spakovati u JAR datoteku, može direktno kroz java -jar komandu da pokrene.
- Java intervju vodič (plaćeni) sadrži originalno pitanje Didi učesnika 2 tehnički drugi intervju: razlika između SpringBoot-a i SpringMVC-a
- Java intervju vodič (plaćeni) sadrži originalno pitanje JD iskustva učesnika 5 Java pozadinski tehnološki prvi intervju: razlika između SpringBoot-a i SpringMVC-a
38.Koja je razlika između Spring Boot-a i Spring-a? (dopuna)
- jula 2024. novo
Sa stanovišta pozicioniranja, Spring je kompletnan framework za razvoj aplikacija, pruža IoC kontejner, AOP i razne funkcionalne module. Spring Boot nije nezavisan framework, već je skelat baziran na Spring framework-u, njegov cilj je da razvoj i implementacija Spring aplikacija postane jednostavni i efikasni.
Spring projekti zahtevaju da mi ručno upravljamo verzijom svakog jar paketa, često nailazimo na probleme konflikta verzija. Na primer ako želimo da koristimo Spring MVC, treba uvesti spring-webmvc, jackson-databind, hibernate-validator itd. gomilu zavisnosti, i osigurati kompatibilnost verzija. Spring Boot kroz starter mehanizam rešio ovaj problem, samo treba uvesti spring-boot-starter-web ovu jednu zavisnost, on sadržai sve vezane jar pakete, i verzije su testirane, mogu biti kompatibilne.
- Java intervju vodič (plaćeni) sadrži originalno pitanje Xiaomi učesnika F intervju: razlika između Spring Boot-a i Spring-a
- Java intervju vodič (plaćeni) sadrži originalno pitanje OPPO iskustva učesnika 1 intervju: pričajte koja je razlika između Spring-a i Springboot-a
memo: 11. avgusta 2025. izmenjeno do ovde, danas član u VIP grupi razmenjuje mišljenje da, koristeći Ergove projekte, lako prolazi prethodni selekcija životopisa velikih kompanija, uključujući Xiaomi i Meituan.

Spring Cloud
39.Koliko poznajete SpringCloud?
Spring Cloud je zapravo kompletna mikroservisna porodica bazirana na Spring Boot-u, nama pomaže da “spremnu za upotrebu” zapakujemo infrastrukturu distribuovanog sistema, na primer registraciju i otkrivanje servisa, upravljanje konfiguracijom, balansiranje opterećenja, prekidivanje i ograničavanje toka, praćenje lanca itd.
Ja sam više koristio Spring Cloud Alibaba ovu seriju, projekat PmHub je jedan primer, na primer:
- Koristimo Nacos za registraciju servisa i centar konfiguracije, i konfiguracione informacije smo perzistirali u MySQL, tako možemo jedinstveno upravljati registracionim informacijama i konfiguracionim informacijama, i podržava dinamičko osvežavanje konfiguracije.
- Koristimo Gateway za API mrežni prolaz, podržava rutiranje i prosleđivanje, globalne filtere, ograničavanje toka itd. funkcije.
- Koristimo Sentinel za prekid, ograničavanje toka, strategija degradacije, kombinovanje sa poslovnom prilagođenom pravilom je veoma pogodno.
- Koristimo OpenFeign za deklarativni poziv između servisa, više štedi koda od RestTemplate, i jasnije se održava.
- Koristimo Seata za procesiranje distribuovanog transakcija, ovo se često koristi u scenarijima narudžbine, plaćanja, toka odobrenja.

Mislim da je najveća vrednost Spring Cloud-a što je objedinio tehnički stek i programerski model, ne treba nam da sami od nule realizujemo centar registracije, prekidač itd. infrastrukturu.
Šta je mikroservis?
Mikroservis je da veliku, komplikovanu monolit aplikaciju razbijemo u male servise nezavisno raspoređene oko poslovnih funkcija, svaki servis održava svoje podatke i logiku, servisi međusobno saradjuju kroz mehanizam lake komunikacije (na primer gRPC).

Ključna vrednost mikroservisa mislim je: granice između poslovnih funkcija su jasnije, različiti timovi mogu nezavisno da razvijaju, raspoređuju, proširuju određenu funkciju, neće zbog male izmene morati ponovo da lansiraju ceo sistem.
Kao projekat PmHub razbijen je iz monolita u mikroservise, uključuje pokretanje mrežnog prolaza, autentifikaciju, proces, upravljanje projektima, generisanje koda itd. više servisa.

- Java intervju vodič (plaćeni) sadrži originalno pitanje BYD učesnika 1 intervju: koliko poznajete SpringCloud?
memo: 12. avgusta 2025. izmenjeno do ovde, danas prilikom pomoći članu da uredi životopis, sreo sam člana koji je rekao: zahvalan Erge-u na izmene mog životopisa, bez Erge-a apsolutno ne bi mogao ući u ByteDance. Nakon što sam pročitao, zaista sam vrlo pogođen, osećam da stvari koje radim zaista imaju značaj.

Dopuna
40.Da li znate SpringTask?
SpringTask je laki framework za planiranje zadataka koji Spring framework pruža, dozvoljava nam programerima da kroz jednostavne anotacije konfigurišemo i upravljamo planiranim zadacima.
Korišćenje je takođe veoma pogodno, prvo koristite @EnableScheduling da omogućite podršku planiranih zadataka.

Zatim na metodi kojoj treba planirani zadatak dodajte @Scheduled anotaciju, podržava fixedRate, fixedDelay i cron izraz. U projektu stvarne prakse Tech Pai, koristili smo cron izraz da svakog dana u ponoć osvežavamo sitemap članaka.
@Scheduled(cron = "0 15 5 * * ?")
public void autoRefreshCache() {
log.info("Počinjem osvežavanje URL adrese sitemap.xml, kako bih izbegao probleme neusklađenosti podataka!");
refreshSitemap();
log.info("Osvežavanje završeno!");
}Ako SpringTask zauzima previše resursa, koje su alternative za rešavanje? (dopuna)
- maja 2024. novo
Prvo treba da analiziramo razlog visokog zauzeća resursa SpringTask-a.
Podrazumevano, SpringTask koristi jednu nit za izvršavanje svih planiranih zadataka, ako neki zadatak dugo traje ili je broj zadataka velik, dolazi do blokiranja. Pored toga, on je baziran na memoriji, sve informacije o zadacima se čuvaju u JVM-u, nakon restartovanja aplikacije stanje zadataka se gubi.
Takođe možemo kroz konfiguraciju niti bafer da rešimo ovaj problem.
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}Dodatno, možemo migrirati SpringTask u druge framework-e za planiranje zadataka, na primer Quartz, XXL-JOB itd.
Quartz je moćniji, podržava klaster, perzistenciju, fleksibilne strategije planiranja. Takođe može perzistirati informacije o zadacima u bazu podataka, podržava klaster implementaciju, kada jedan čvor padne drugi član može preuzeti zadatak.
Korišćenje XXL-JOB je rešnije rešenje u distribuiranim scenarima, ima nezavisan centar za planiranje, konfiguracija i izvršavanje zadataka mogu biti razdvojene; podržava sečićeno izvršavanje, veliki zadatak može biti podeljen na više podzadataka paralelno procesiranih.
/**
* 2. Zadatak sečićenog emitovanja
*/
@XxlJob("shardingJobHandler")
public void shardingJobHandler() throws Exception {
// Parametri sečićenja
int shardIndex = com.xxl.job.core.context.XxlJobHelper.getShardIndex();
int shardTotal = com.xxl.job.core.context.XxlJobHelper.getShardTotal();
logger.info("Zadatak sečićenog emitovanja počinje izvršavanje, trenutni redni broj sečića = {}, ukupan broj sečića = {}", shardIndex, shardTotal);
// Procesiranje poslovne logike, procesirajte različite podatke na osnovu parametara sečićenja
for (int i = shardIndex; i < 100; i += shardTotal) {
logger.info(" {}. sečić, procesiram podatke: {}", shardIndex, i);
// Simulirajte vreme procesiranja podataka
TimeUnit.MILLISECONDS.sleep(100);
}
logger.info("Izvršavanje zadatka sečićenog emitovanja završeno");
}
- Java intervju vodič (plaćeni) sadrži originalno pitanje WeBank učesnika 1 Java pozadinski prvi intervju: da li znate SpringTask?
- Java intervju vodič (plaćeni) sadrži originalno pitanje Alibaba iskustva učesnika 1 Xianyu pozadinski prvi intervju: istek vremena narudžbine, springtask zauzima previše resursa, koje su alternative za rešavanje?
memo: 16. avgusta 2025. izmenjeno do ovde, danas prilikom pomoći članu da uredi životopis, sreo sam člana koji je rekao: prilikom letnje prakse koristio Tech Pai, takođe je tražio od Erge-a da izmeni životopis, konačno dobio praktičnu priliku Helao, vrlo zahvalan. Zaista, svaki put kad naiđem na takvu povratnu informaciju člana, vrlo sam srećan.

41.Da li znate Spring Cache?
Spring Cache je skup apstrakcija keša koju Spring framework pruža, kroz pružanje jedinstvenog interfejsa podržava različite implementacije keša, kao Redis, Caffeine itd.

Nama samo treba da dodamo nekoliko anotacija na metodu, Spring će automatski procesirati čuvanje i učitavanje keša, ovaj deklarativni način korišćenja keša omogućava da se poslovni kod i logika keša potpuno razdvoje.
Najčešće korišćena anotacija je @Cacheable, koristi se da označi da povratna vrednost metode treba da bude keširana.
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
return userDao.findById(id);
}Nakon prvog izvršavanja metode rezultat će biti keširan, naredni pozivi će direktno vraćati iz keša, neće izvršavati telo metode.
Takođe postoji @CacheEvict anotacija, koristi se za čišćenje keša pre ili posle izvršavanja metode.
@CacheEvict(value = "users", key = "#id")
public void deleteUserById(Long id) {
userDao.deleteById(id);
}Spring Cache je realizovan kroz AOP, kroz presretanje poziva metode, pre i posle poziva ubacuje logiku keša. Potrebno nam je u konfiguraciji prvo omogućiti funkciju keša.
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
RedisCacheManager.Builder builder = RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory())
.cacheDefaults(cacheConfiguration());
return builder.build();
}
}Koja je razlika između Spring Cache-a i Redis-a?
Razlika između Spring Cache-a i Redis-a je zapravo razlika između apstraktnog sloja i konkretne implementacije. Spring Cache samo pruža jedinstven skup interfejsa i anotacija za upravljanje kešom, sam ne pruža mogućnost keša, dok je Redis konkretna implementacija keša.
U nivou korišćenja, Spring Cache je jednostavniji, samo treba dodati anotaciju na metodu, framework će nam automatski procesirati.
@Cacheable("users")
public User getUser(Long id) {
return userDao.findById(id);
}Ako koristite Redis, nam treba ručno da procesiramo logiku keša:
public User getUser(Long id) {
String key = "user:" + id;
User user = (User) redisTemplate.opsForValue().get(key);
if (user == null) {
user = userDao.findById(id);
redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
}
return user;
}U stvarnim projektima, obično biram da koristim Spring Cache za procesiranje nekih jednostavnih poslovnih keševa, ali za neke komplikovane poslovne scenarije, za komplikovanu poslovnu logiku, na primer distribušana brava, brojača, rang lista itd., direktno ću koristiti Redis.
Zašto je i dalje potreban Spring Cache ako postoji Redis?
Iako je Redis veoma moćan, Spring Cache može pojednostaviti upravljanje kešom. Mi direktno dodajemo anotaciju na metodu da realizujemo logiku keša, smanjujemo količinu koda za ručno manipulisanje Redis-om.
@Cacheable("users")
public User getUser(Long id) {
return userDao.findById(id);
}Pored toga, Spring Cache takođe može fleksibilno prebaciti podređenu implementaciju keša, na primer iz Redis u Caffeine.
Pričajte osnovni princip Spring Cache-a?
Osnova Spring Cache-a je realizovana kroz AOP. Kada na metodu označimo @Cacheable anotaciju, Spring će pri pokretanju projekta skenirati ove anotacije, i kreiraće proxy objekte. Proxy objekat će presresti sve pozive metoda, pre i posle izvršavanja metode ubaciti logiku vezanu za keš.

Specifičan proces izvršavanja je ovakav:
Kada korisnik poziva metodu označenu anotacijom keša, zapravo poziva proxy objekat, a ne originalni objekat.
Intercepter CacheInterceptor u proxy objektu će prvo razložiti anotaciju keša na metodi, dobiti informacije o konfiguraciji kao što su naziv keša, pravilo generisanja ključa, vreme isteka itd. Zatim na osnovu tipa anotacije izvršava različite strategije keša, na primer @Cacheable će prvo potražiti podatke u kešu, ako pronađe direktno vraća, ne izvršava originalnu metodu; ako ne pronađe, izvršava originalnu metodu da dobije rezultat, zatim rezultat smešta u keš i vraća.
Generisanje ključa keša je završeno kroz KeyGenerator komponentu, podrazumevano će generisati ključ na osnovu parametara metode. Ako u anotaciji navedemo atribut key, Spring će koristiti SpEL expression engine da razloži ovaj izraz, kombinujući parametre metode, povratnu vrednost i druge kontekstne informacije da izračuna specifičnu vrednost ključa.
Podređeno skladištenje keša se upravlja kroz ove apstraktne interfejse CacheManager i Cache. CacheManager je odgovoran za upravljanje višestrukih oblasti keša, svaka instanca Cache odgovara specifičnoj oblasti keša.
Bez obzira da li koristimo Redis, Caffeine ili druge tehnologije keša, moramo implementirati ova dva interfejsa. Na ovaj način Spring Cache može na jedinstven način da operiše različitim implementacijama keša, realizovao je vrlo dobro dekristplje.
- Java intervju vodič (plaćeni) sadrži originalno pitanje Meituan učesnika 9 prvi intervju: predstavite springcache i redis? U kojim scenarijima se primenjuju springcache i redis? Zašto je potrebno springcahe ako postoji redis? Osnovni princip springcache-a, na čemu je baziran?
memo: danas prilikom uređivanja životopisa članova, član je rekao, prilikom traženja praktičnog rada takođe je tražio od Erge-a da izmeni životopis, konačno je uspešno našao, vrlo mi se dopada ovakva povratna informacija, pokazuje da je moja uložena srca imala povraćaja, zahvalan svakom putanju reputaciji učenika.

Puno dva meseca, drugo izdanje Intervju pobede Spring deo je konačno završeno, ovo izdanje se može reći da je potpuno prepisano, svaki dan sam uložio mnogo energije u njega, može se reći da je promenjeno iz osnova, osećam "dva meseca kasnije, pogledaj drugačije" (od 13.000 reči eksplodiralo na 34.000 reči, dok dodajem obroke, razlikujem visokofrekventnu i niskofrekventnu verziju).

Na internetu zaista postoji mnogo osmovnih zadataka, neki su i plaćeni, mislim da je to dobra stvar, može svima pružiti više izbora, ali kvalitet Intervju pobede oni koji razumeju razumeju.

Drugo izdanje Intervju pobede je na osnovu početne verzije gosta planete San Fen E, dodalo Ergove vlastite misli, dodalo rezultate posle više od 1000 stvarnih iskustava intervjua, i od 24. generacije do 25. generacije, zatim 26. generacije, pomoglo mnogo prijatelja. Buduće 27, 28 generacije će takođe imati koristi, time dobijaju željene ponude.
Vreća mogu pomoći svima, vrlo sam zadovoljan, i u procesu rekonstrukcije Intervju pobede, sam mnogo narastao, mnoge slabije osnovne veze su ojačane, stoga drugo izdanje Intervju pobede nije samo dar za sve, već i zapis moje tehničke transformacije.



Često mislim da sam zen tip osobe, ne želim da se nadmetaš s drugima za viš ili niži, ne želim namerno da promovišem svoja dela.
Volim da čekam da cvetaju.
Ako mislite da je Intervju pobeda dobra, možete reći mlađim kolegama i studentkinjama da postoji ovaj besplatni materijal za učenje, pomožite mi da stvorim reputaciju.
Još uvek ću nastaviti da unapređujem, ne znam kada će stići treće izdanje, ali ću se potrati da učinim sve što mogu.
Neka svi imaju svetlu budućnost.
Uključio sam Ergov Java napredni put, JVM napredni put, napredni put konkurentnog programiranja, kao i sve verzije Intervju pobede, pokriva Java osnove, Java kolekcije, Java konkurentnost, JVM, Spring, MyBatis, računarske mreže, operativni sistemi, MySQL, Redis, RocketMQ, distribuirane sisteme, mikroservise, dizajn obrazce, Linux itd. ukupno 16 velikih tema, ukupno preko 400.000 reči, 2000+ ručno crtanih crteža, može se reći da je iskreno puno.
Ovaj put su i dalje tri verzije, svetla, tamna i epub verzija. Prikažu vam jednu epub verziju, neki prijatelji su vrlo hitne ove verzije, pa sam zadovoljio sve.

Slike i tekstovi detaljno objašnjavaju 41 visokofrekventnih pitanja Spring intervjua, ovaj put ću pregaziti intervjua, mislim da je sigurno (ručni pas). Organizator: Chenmo Wang Er, kliknite na link preuzimanja, autor: San Fen E, kliknite na originalni link.
Ništa me ne zaustavlja — osim cilja, čak i ako na obali ima ruža, hladovine, mirnih luka, ja sam brod bez veza.
Sadržaj serije:
- Intervju pobeda Java SE deo 👍
- Intervju pobeda Java okvir zbirka 👍
- Intervju pobeda Java konkurentno programiranje 👍
- Intervju pobeda JVM deo 👍
- Intervju pobeda Spring deo 👍
- Intervju pobeda Redis deo 👍
- Intervju pobeda MyBatis deo 👍
- Intervju pobeda MySQL deo 👍
- Intervju pobeda Operativni sistemi deo 👍
- Intervju pobeda Računarske mreže deo 👍
- Intervju pobeda RocketMQ deo 👍
- Intervju pobeda Distribuirani sistemi deo 👍
- Intervju pobeda Mikroservisi deo 👍
- Intervju pobeda Dizajn obrazci deo 👍
- Intervju pobeda Linux deo 👍
- Intervju pobeda OpenClaw deo 👍
- Intervju pobeda Vještine deo 👍
