Druge često korišćene Java alatke: IPUtil, CollectionUtils, MDC, ClassUtils, BeanUtils, ReflectionUtils
Pored izvornih Java alatki koje smo već pomenuli, kao što su Arrays, Objects, Collections, Scanner i slično, postoje i alatke trećih strana, poput Hutool, Guava i drugih, kao i alatke koje danas predstavljamo — IpUtil, CollectionUtils, StringUtils, MDC, ClassUtils, BeanUtils, ReflectionUtils i tako dalje — koje u velikoj meri mogu povećati našu produktivnost.
Naravno, ako dobro proučite njihov izvorni kod, to će znatno pomoći i izgradnji vaših tehničkih temelja.
IpUtil: dobijanje IP adrese lokalne mašine
Dobijanje IP adrese lokalne mašine prilično je čest zahtev, na primer pri poslovnim alarmima, gde se može priložiti IP mašine na kojoj je nastao problem, kako bi se moglo direktno ući u logove i locirati problem. E, sada se nameće pitanje: kako dobiti IP mašine?
1. Osnovna metoda
Kako dobiti IP mašine? Ako poznajete alatku InetAddress, vrlo je lako napisati jednostavnu alatku, na primer:
public static String getLocalIP() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}Da li implementacija iznad ima problema?
Naravno da nema. Pokrenite je na mojoj lokalnoj mašini i na serveru kod Aliyun-a i nema problema — ispisuje očekivanu IP adresu.
Snimak ekrana nakon pokretanja na lokalnoj mašini:

Snimak ekrana nakon pokretanja na Aliyun mašini:

2. Napredna verzija
Učinićemo malu izmenu kako bismo dobili IPv4 adresu. Izvorni kod je sledeći:
public static String getLocalIpByNetcard() {
try {
// Enumerišu se svi mrežni interfejsi
for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements(); ) {
// Uzima se trenutni mrežni interfejs
NetworkInterface item = e.nextElement();
// Prolazi se kroz sve adrese trenutnog mrežnog interfejsa
for (InterfaceAddress address : item.getInterfaceAddresses()) {
// Ignorišu se loopback adrese i mrežni interfejsi koji nisu aktivni
if (item.isLoopback() || !item.isUp()) {
continue;
}
// Ako je trenutna adresa IPv4 adresa, vraća se njena tekstualna reprezentacija
if (address.getAddress() instanceof Inet4Address) {
Inet4Address inet4Address = (Inet4Address) address.getAddress();
return inet4Address.getHostAddress();
}
}
}
// Ako nije pronađena nijedna IPv4 adresa, vraća se adresa lokalnog hosta
return InetAddress.getLocalHost().getHostAddress();
} catch (SocketException | UnknownHostException e) {
// Baca se izuzetak u toku izvršavanja
throw new RuntimeException(e);
}
}Treba napomenuti da ovaj kod vraća samo IPv4 adresu lokalne mašine i to samo prvu adresu koja ispunjava uslov. Ako lokalna mašina ima više mrežnih interfejsa ili svaki interfejs ima više adresa, možda neće vratiti očekivanu adresu. Pored toga, ako ne pronađe nijednu IPv4 adresu, vratiće adresu lokalnog hosta.
Ponovo testirano, izlaz je sledeći:

3. Kompletna alatka
import java.net.*;
import java.util.Enumeration;
public class IPUtil {
public static final String DEFAULT_IP = "127.0.0.1";
/**
* Vraća adresu prvog mrežnog interfejsa kao internu IPv4 adresu, kako bi se izbeglo vraćanje 127.0.0.1
*
* @return prva interna IPv4 adresa koja ispunjava uslov
*/
public static String getLocalIpByNetcard() {
try {
// Enumerišu se svi mrežni interfejsi
for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements(); ) {
// Uzima se trenutni mrežni interfejs
NetworkInterface item = e.nextElement();
// Prolazi se kroz sve adrese trenutnog mrežnog interfejsa
for (InterfaceAddress address : item.getInterfaceAddresses()) {
// Ignorišu se loopback adrese i mrežni interfejsi koji nisu aktivni
if (item.isLoopback() || !item.isUp()) {
continue;
}
// Ako je trenutna adresa IPv4 adresa, vraća se njena tekstualna reprezentacija
if (address.getAddress() instanceof Inet4Address) {
Inet4Address inet4Address = (Inet4Address) address.getAddress();
return inet4Address.getHostAddress();
}
}
}
// Ako nije pronađena adresa koja ispunjava uslov, vraća se adresa lokalnog hosta
return InetAddress.getLocalHost().getHostAddress();
} catch (SocketException | UnknownHostException e) {
throw new RuntimeException(e);
}
}
/**
* Vraća adresu lokalnog hosta
*
* @return adresa lokalnog hosta
*/
public static String getLocalIP() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}Klasa IPUtil definiše dve metode: getLocalIpByNetcard() i getLocalIP(). Prva dobija internu IPv4 adresu lokalne mašine i izbegava vraćanje 127.0.0.1. Druga dobija adresu lokalnog hosta; ako lokalna mašina ima više IP adresa, može vratiti bilo koju od njih.
MDC: alatka za bezbedan prenos parametara između niti
MDC je klasa u paketu org.slf4j; njen pun naziv je Mapped Diagnostic Context, a možemo je smatrati kontejnerom bezbednim po pitanju niti za čuvanje dijagnostičkih logova.
MDC je u svojoj osnovi iskoristio ThreadLocal za čuvanje podataka.
Možemo ga koristiti za prenos parametara.
Na primer, zamislimo sledeći scenario: kada koristimo RestTemplate za poziv udaljenog interfejsa, ponekad je potrebno proslediti informacije u header-u, kao što su traceId, source i slično, kako bismo pri pretrazi logova mogli povezati celu lanac zahteva u jednu celinu i brzo locirati problem.
Ovakav poslovni scenario može se realizovati kroz interfejs ClientHttpRequestInterceptor, i to na sledeći način:
Prvi korak: definisati LogFilter koji obuhvata sve zahteve interfejsa i postavlja traceId u MDC:
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
MdcUtil.add(UUID.randomUUID().toString());
System.out.println("Evidencija loga zahteva");
chain.doFilter(request, response);
System.out.println("Evidencija loga odgovora");
}
@Override
public void destroy() {
}
}Drugi korak: implementirati interfejs ClientHttpRequestInterceptor, iz MDC preuzeti traceId trenutnog zahteva, a zatim ga postaviti u header:
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().set("traceId", MdcUtil.get());
return execution.execute(request, body);
}
}Treći korak: definisati konfiguracionu klasu u kojoj se konfiguriše gore definisana klasa RestTemplateInterceptor:
@Configuration
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList(restTemplateInterceptor()));
return restTemplate;
}
@Bean
public RestTemplateInterceptor restTemplateInterceptor() {
return new RestTemplateInterceptor();
}
}MdcUtil zapravo koristi alatku MDC za čuvanje i dobijanje traceId unutar ThreadLocal-a:
public class MdcUtil {
private static final String TRACE_ID = "TRACE_ID";
public static String get() {
return MDC.get(TRACE_ID);
}
public static void add(String value) {
MDC.put(TRACE_ID, value);
}
}Naravno, u ovom primeru nije prikazano mesto gde se metod add klase MdcUtil konkretno poziva. Možemo pre izvršavanja metode interfejsa u filteru generisati traceId, pozvati metod add klase MdcUtil da ga doda u MDC, a zatim na drugim mestima unutar istog zahteva metod get klase MdcUtil možemo koristiti da dobijemo taj traceId.
Osnovni razlog zbog kojeg MDC može čuvati parametre poput traceId jeste taj što, kada korisnički zahtev stigne do servera aplikacije, Tomcat iz svog bazena niti dodeljuje jednu nit da obradi taj zahtev.
Tokom celog trajanja tog zahteva, parametri sačuvani u ThreadLocal-u unutar MDC-a pripadaju isključivo toj niti, tako da ne nastaju problemi u vezi sa bezbednošću niti.
ClassUtils
Klasa ClassUtils u paketu org.springframework.util okvira Spring sadrži mnogo funkcija koje će nas obradovati.
Ona obuhvata veoma mnogo praktičnih metoda vezanih za klase i objekte.
Dobijanje svih interfejsa jednog objekta
Ako želite da dobijete sve interfejse nekog objekta, možete koristiti metod getAllInterfaces klase ClassUtils. Na primer:
Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(new User());Dobijanje naziva paketa neke klase
Ako želite da dobijete naziv paketa neke klase, možete koristiti metod getPackageName klase ClassUtils. Na primer:
String packageName = ClassUtils.getPackageName(User.class);
System.out.println(packageName);Provera da li je neka klasa unutrašnja klasa
Ako želite da proverite da li je neka klasa unutrašnja klasa, možete koristiti metod isInnerClass klase ClassUtils. Na primer:
System.out.println(ClassUtils.isInnerClass(User.class));Provera da li je objekat proxy objekat
Ako želite da proverite da li je neki objekat proxy objekat, možete koristiti metod isCglibProxy klase ClassUtils. Na primer:
System.out.println(ClassUtils.isCglibProxy(new User()));ClassUtils ima još mnogo korisnih metoda koje čekaju da ih otkrijete. Zainteresovani drugari mogu pogledati sadržaj ispod:

BeanUtils
Spring nam pruža alatku za rad sa JavaBean objektima; nalazi se u paketu org.springframework.beans i zove se BeanUtils.
Hajde da zajedno vidimo kakva nas iznenađenja ova alatka može priuštiti.
Kopiranje svojstava objekta
Da li vam se nekada desila ovakva potreba: sve atribute nekog objekta prekopirati u drugi objekat. Tada možete koristiti metod copyProperties klase BeanUtils. Na primer:
User user1 = new User();
user1.setId(1L);
user1.setName("Chenmo Wang Er");
user1.setAddress("Kina");
User user2 = new User();
BeanUtils.copyProperties(user1, user2);
System.out.println(user2);Instanciranje neke klase
Ako želite preko refleksije da instancirate objekat neke klase, možete koristiti metod instantiateClass klase BeanUtils. Na primer:
User user = BeanUtils.instantiateClass(User.class);
System.out.println(user);Dobijanje zadate metode zadate klase
Ako želite da dobijete neku zadatu metodu neke klase, možete koristiti metod findDeclaredMethod klase BeanUtils. Na primer:
Method declaredMethod = BeanUtils.findDeclaredMethod(User.class, "getId");
System.out.println(declaredMethod.getName());Dobijanje parametara zadate metode
Ako želite da dobijete parametre neke metode, možete koristiti metod findPropertyForMethod klase BeanUtils. Na primer:
Method declaredMethod = BeanUtils.findDeclaredMethod(User.class, "getId");
PropertyDescriptor propertyForMethod = BeanUtils.findPropertyForMethod(declaredMethod);
System.out.println(propertyForMethod.getName());Ako vas BeanUtils posebno zanima, možete pogledati sadržaj ispod:

ReflectionUtils
Ponekad u projektu moramo da koristimo refleksiju; ako se oslonimo na najprimitivniji pristup, količina koda biće velika i vrlo nezgodna, jer treba obraditi gomilu izuzetaka i pitanja prava pristupa.
Dobra vest je da nam Spring pruža alatku ReflectionUtils, koja se nalazi u paketu org.springframework.util.
Dobijanje metode
Ako želite da dobijete neku metodu neke klase, možete koristiti metod findMethod klase ReflectionUtils. Na primer:
Method method = ReflectionUtils.findMethod(User.class, "getId");Dobijanje polja
Ako želite da dobijete neko polje neke klase, možete koristiti metod findField klase ReflectionUtils. Na primer:
Field field = ReflectionUtils.findField(User.class, "id");Izvršavanje metode
Ako želite preko refleksije da pozovete neku metodu i prosledite joj parametre, možete koristiti metod invokeMethod klase ReflectionUtils. Na primer:
ReflectionUtils.invokeMethod(method, springContextsUtil.getBean(beanName), param);Provera da li je polje konstanta
Ako želite da proverite da li je neko polje konstanta, možete koristiti metod isPublicStaticFinal klase ReflectionUtils. Na primer:
Field field = ReflectionUtils.findField(User.class, "id");
System.out.println(ReflectionUtils.isPublicStaticFinal(field));Provera da li je metod equals
Ako želite da proverite da li je neka metoda metoda equals, možete koristiti metod isEqualsMethod klase ReflectionUtils. Na primer:
Method method = ReflectionUtils.findMethod(User.class, "getId");
System.out.println(ReflectionUtils.isEqualsMethod(method));Naravno, ova klasa ima još niz zanimljivih metoda; zainteresovani prijatelji mogu pogledati sadržaj ispod:

Referentni link: https://juejin.cn/post/7102418518599008286 Autor: Su San, urednik: Chenmo Wang Er
