Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the coding skills of Spring

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "what are the code skills of Spring". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what are the code skills of Spring".

How to get spring Container object

1. Implement the BeanFactoryAware interface

Service public class PersonService implements BeanFactoryAware {private BeanFactory beanFactory; @ Override public void setBeanFactory (BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;} public void add () {Person person = (Person) beanFactory.getBean ("person");}}

You can get the spring container object from the setBeanFactory method by implementing the BeanFactoryAware interface and then overriding the spring method.

two。 Implement the ApplicationContextAware interface

Service public class PersonService2 implements ApplicationContextAware {private ApplicationContext applicationContext; @ Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;} public void add () {Person person = (Person) applicationContext.getBean ("person");}}

Implement the ApplicationContextAware interface, and then override the setApplicationContext method, from which you can also get the spring container object.

3. Implement the ApplicationListener interface

Service public class PersonService3 implements ApplicationListener {private ApplicationContext applicationContext; @ Override public void onApplicationEvent (ContextRefreshedEvent event) {applicationContext = event.getApplicationContext ();} public void add () {Person person = (Person) applicationContext.getBean ("person");}}

To implement the ApplicationListener interface, it is important to note that the interface receives generics of the ContextRefreshedEvent class, and then overrides the onApplicationEvent method, from which the spring container object can also be obtained.

In addition, I have to mention the Aware interface, which is actually an empty interface and does not contain any methods.

It represents the perceived meaning, and the specified object can be obtained through such interfaces, such as:

Obtain BeanFactory through BeanFactoryAware

Obtain ApplicationContext through ApplicationContextAware

Get BeanName and so on through BeanNameAware

Aware API is a commonly used feature, which currently includes the following features:

How to initialize bean

There are three ways to initialize bean in spring:

Specify the init-method method in xml

Use @ PostConstruct annotations

Implement the InitializingBean interface

The first method is so old that not many people use it now, so the specific usage will not be introduced.

1. Use @ PostConstruct annotations

@ Service public class AService {@ PostConstruct public void init () {System.out.println ("= = initialization = =");}}

Add @ PostConstruct annotations to the methods that need to be initialized so that you have the ability to initialize.

two。 Implement the InitializingBean interface

@ Service public class BService implements InitializingBean {@ Override public void afterPropertiesSet () throws Exception {System.out.println ("= = initialization = =");}}

Implement the InitializingBean interface and override the afterPropertiesSet method, which can complete the initialization function.

Here, by the way, is an interesting question: what is the order in which init-method, PostConstruct, and InitializingBean are executed?

The key code that determines the order in which they are called is in the initializeBean method of the AbstractAutowireCapableBeanFactory class.

In this code, the postProcessBeforeInitialization method of BeanPostProcessor is called first, and PostConstruct is implemented through InitDestroyAnnotationBeanPostProcessor, which is a BeanPostProcessor, so PostConstruct executes first.

The code in the invokeInitMethods method:

It is decided to call InitializingBean first and then init-method.

So it is concluded that the order in which they are called is:

3. Customize your own Scope

We all know that there are only two types of Scope supported by spring by default:

For a single case of singleton, the bean obtained from the spring container is the same object each time.

There are many cases of prototype, and each time the bean obtained from the spring container is a different object.

Spring web has extended Scope by adding:

RequestScope gets the same bean from the spring container in the same request.

SessionScope the bean obtained from the spring container for the same session is the same object.

Even so, some scenarios do not meet our requirements.

For example, what if the bean we want to get from the spring container in the same thread is the same object?

This requires a custom Scope.

The first step is to implement Scope interface:

Public class ThreadLocalScope implements Scope {private static final ThreadLocal THREAD_LOCAL_SCOPE = new ThreadLocal (); @ Override public Object get (String name, ObjectFactory objectFactory) {Object value = THREAD_LOCAL_SCOPE.get (); if (value! = null) {return value;} Object object = objectFactory.getObject (); THREAD_LOCAL_SCOPE.set (object); return object } @ Override public Object remove (String name) {THREAD_LOCAL_SCOPE.remove (); return null;} @ Override public void registerDestructionCallback (String name, Runnable callback) {} @ Override public Object resolveContextualObject (String key) {return null;} @ Override public String getConversationId () {return null;}}

Step 2: inject the newly defined Scope into the spring container:

@ Component public class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@ Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException {beanFactory.registerScope ("threadLocalScope", new ThreadLocalScope ());}

The third step uses the newly defined Scope:

@ Scope ("threadLocalScope") @ Service public class CService {public void add () {}}

Four, don't say FactoryBean is useless.

Speaking of FactoryBean, I have to mention BeanFactory, because interviewers always like to ask the difference between them.

The top-level interface of the BeanFactory:spring container to manage the factory of bean.

FactoryBean: not an ordinary factory bean, it hides the details of instantiating some complex Bean and brings convenience to upper-level applications.

If you look at the spring source code, you will find that it has more than 70 places to use the FactoryBean interface.

The above picture is enough to illustrate the importance of the interface, please don't ignore it, okay?

In particular: the SqlSessionFactory object of mybatis is created through the SqlSessionFactoryBean class.

Let's define our own FactoryBean together:

@ Component public class MyFactoryBean implements FactoryBean {@ Override public Object getObject () throws Exception {String data1 = buildData1 (); String data2 = buildData2 (); return buildData3 (data1, data2);} private String buildData1 () {return "data1";} private String buildData2 () {return "data2" } private String buildData3 (String data1, String data2) {return data1 + data2;} @ Override public Class getObjectType () {return null;}}

Get the FactoryBean instance object:

@ Service public class MyFactoryBeanService implements BeanFactoryAware {private BeanFactory beanFactory; @ Override public void setBeanFactory (BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;} public void test () {Object myFactoryBean = beanFactory.getBean ("myFactoryBean"); System.out.println (myFactoryBean); Object myFactoryBean1 = beanFactory.getBean ("& myFactoryBean"); System.out.println (myFactoryBean1);}}

GetBean ("myFactoryBean"); gets the object returned by the getObject method in the MyFactoryBeanService class

GetBean ("& myFactoryBean"); gets the MyFactoryBean object.

5 easy customization of type conversion

Spring currently supports 3 type converters:

Converter: convert S-type objects to T-type objects

ConverterFactory: convert S-type objects to R-type and subclass objects

GenericConverter: it supports the conversion of multiple source and target types, as well as the context of source and target types, which allows you to convert based on comments or information on attributes.

These three types of converters use different scenarios, let's take Converter as an example. Suppose: in the entity object that receives parameters in the interface, there is a field of type Date, but the actual parameter is a string type: 2021-01-03 10:20:15, what should I do?

The first step is to define an entity User:

@ Data public class User {private Long id; private String name; private Date registerDate;}

The second step is to implement Converter interface:

Public class DateConverter implements Converter {private SimpleDateFormat simpleDateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); @ Override public Date convert (String source) {if (source! = null & &! ".equals (source)) {try {simpleDateFormat.parse (source);} catch (ParseException e) {e.printStackTrace () }} return null;}}

Third, inject the newly defined type converter into the spring container:

Configuration public class WebConfig extends WebMvcConfigurerAdapter {@ Override public void addFormatters (FormatterRegistry registry) {registry.addConverter (new DateConverter ());}}

Step 4, call the interface

@ RequestMapping ("/ user") @ RestController public class UserController {@ RequestMapping ("/ save") public String save (@ RequestBody User user) {return "success";}}

The registerDate field in the User object is automatically converted to the Date type when the interface is requested.

Six spring mvc interceptor, all said good

Spring mvc interceptor compared to the root spring interceptor, it can get web object instances such as HttpServletRequest and HttpServletResponse.

The top-level interface of the spring mvc interceptor is HandlerInterceptor, which contains three methods:

PreHandle target method execution before execution

Execute after postHandle target method execution

Execute when the afterCompletion request is completed

For convenience, we usually use the HandlerInterceptorAdapter class, the implementation class of the HandlerInterceptor interface.

If you have permission authentication, logging, statistical scenarios, you can use this interceptor.

The first step is to inherit the HandlerInterceptorAdapter class definition interceptor:

Public class AuthInterceptor extends HandlerInterceptorAdapter {@ Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String requestrequestUrl = request.getRequestURI (); if (checkAuth (requestUrl)) {return true;} return false;} private boolean checkAuth (String requestUrl) {System.out.println ("= permission check = =") Return true;}}

The second step is to register the interceptor with the spring container:

@ Configuration public class WebAuthConfig extends WebMvcConfigurerAdapter {@ Bean public AuthInterceptor getAuthInterceptor () {return new AuthInterceptor ();} @ Override public void addInterceptors (InterceptorRegistry registry) {registry.addInterceptor (new AuthInterceptor ());}}

The third step is that spring mvc can automatically intercept the interface and verify permissions through the interceptor when requesting the interface.

The interceptor is actually relatively simple, and you can see the calling process in the doDispatch method of the DispatcherServlet class:

By the way, I'm only talking about spring mvc's interceptor, not spring's interceptor, because I'm a little selfish, as I'll know later.

The seven Enable switch smells good.

I don't know if you have ever used annotations starting with Enable, such as EnableAsync, EnableCaching, EnableAspectJAutoProxy, etc., such annotations are like switches. As long as you add such annotations to the configuration class defined by @ Configuration, you can turn on the relevant functions.

Isn't that cool?

Let's implement a switch of our own together:

The first step is to define a LogFilter:

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 {System.out.println ("record request log"); chain.doFilter (request, response); System.out.println ("record response log") } @ Override public void destroy () {}}

The second step is to register LogFilter:

@ ConditionalOnWebApplication public class LogFilterWebConfig {@ Bean public LogFilter timeFilter () {return new LogFilter ();}}

Note that the @ ConditionalOnWebApplication annotation is used here, not directly the @ Configuration annotation.

Third, define the switch @ EnableLog annotation:

@ Target (ElementType.TYPE) @ Retention (RetentionPolicy.RUNTIME) @ Documented @ Import (LogFilterWebConfig.class) public @ interface EnableLog {}

Fourth, simply add the @ EnableLog annotation to the springboot startup class to enable LogFilter to log requests and responses.

The Spring of eight RestTemplate interceptors

When we use RestTemplate to call the remote interface, we sometimes need to transmit information in header, such as traceId,source, so that we can concatenate a complete request link when querying the log and quickly locate the problem.

This business scenario can be implemented through the ClientHttpRequestInterceptor API, as follows:

The first step is to implement the ClientHttpRequestInterceptor interface

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);}}

Second, define the configuration class:

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 actually uses MDC tools to store and obtain traceId in ThreadLocal.

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);}}

Of course, there is no specific call to the add method of the MdcUtil class in this example. We can generate the traceId before executing the interface method in filter, call the add method of the MdcUtil class to add to the MDC, and then get the traceId elsewhere in the same request through the get method of the MdcUtil class.

Nine unified exception handling

In the past, when we were developing an interface, if an exception occurred, in order to give the user a more friendly hint, for example:

@ RequestMapping ("/ test") @ RestController public class TestController {@ GetMapping ("/ add") public String add () {int a = 10 / 0; return "success";}}

If you do not do any processing to request the add API, you will directly report an error:

What? Can the user see the error message directly?

This interaction gives users a very poor experience. To solve this problem, we usually catch exceptions in the interface:

@ GetMapping ("/ add") ublic String add () {String result = "success"; try {int a = 10 / 0;} catch (Exception e) {result = "data exception";} return result

After the interface modification, when an exception occurs, it will prompt: "data exception", which is more user-friendly.

It looks good, but there's a problem.

It's fine if it's just one interface, but if there are hundreds or thousands of interfaces in the project, do you need to add exception catch code?

The answer is no, and global exception handling comes in handy: RestControllerAdvice.

@ RestControllerAdvice public class GlobalExceptionHandler {@ ExceptionHandler (Exception.class) public String handleException (Exception e) {if (e instanceof ArithmeticException) {return "data exception";} if (e instanceof Exception) {return "server internal exception";} return null;}}

As long as the exception is handled in the handleException method, it can be safely used in the business interface, and there is no need to catch the exception (someone handled it uniformly). That was awesome.

Ten asynchronies can be so elegant.

In the past, when we used to use the asynchronous feature, there were usually three ways:

Inherit the Thread class

Implement the Runable interface

Use thread pool

Let's review together:

1. Inherit the Thread class

Public class MyThread extends Thread {@ Override public void run () {System.out.println ("= call MyThread===");} public static void main (String [] args) {new MyThread () .start ();}}

two。 Implement the Runable interface

Public class MyWork implements Runnable {@ Override public void run () {System.out.println ("= call MyWork===");} public static void main (String [] args) {new Thread (new MyWork ()) .start ();}}

3. Use thread pool

Public class MyThreadPool {private static ExecutorService executorService = new ThreadPoolExecutor (1,5,60, TimeUnit.SECONDS, new ArrayBlockingQueue); static class Work implements Runnable {@ Override public void run () {System.out.println ("= call work===");} public static void main (String [] args) {try {executorService.submit (new MyThreadPool.Work ()) } finally {executorService.shutdown ();}

There's nothing wrong with these three ways to implement asynchrony, but spring has helped us extract some common areas, and we no longer need to inherit the Thread class or implement the Runable interface.

How to spring asynchronous function?

The first step is to add the @ EnableAsync annotation to the springboot project startup class.

@ EnableAsync @ SpringBootApplication public class Application {public static void main (String [] args) {new SpringApplicationBuilder (Application.class) .web (WebApplicationType.SERVLET) .run (args);}}

The second step is to add @ Async annotations to the methods that need to be asynchronous:

@ Service public class PersonService {@ Async public String get () {System.out.println ("= add=="); return "data";}}

Then call personService.get () where you use it; and you have asynchronous functionality. Isn't that amazing?

By default, spring creates a thread for our asynchronous method to execute, and if the method is called too many times, a large number of threads need to be created, which will lead to a waste of resources.

At this point, we can define a thread pool, and asynchronous methods will be automatically committed to the thread pool for execution.

@ Configuration public class ThreadPoolConfig {@ Value ("${thread.pool.corePoolSize:5}") private int corePoolSize; @ Value ("${thread.pool.maxPoolSize:10}") private int maxPoolSize; @ Value ("${thread.pool.queueCapacity:200}") private int queueCapacity; @ Value ("${thread.pool.keepAliveSeconds:30}") private int keepAliveSeconds @ Value ("${thread.pool.threadNamePrefix:ASYNC_}") private String threadNamePrefix; @ Bean public Executor MessageExecutor () {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor (); executor.setCorePoolSize (corePoolSize); executor.setMaxPoolSize (maxPoolSize); executor.setQueueCapacity (queueCapacity); executor.setKeepAliveSeconds (keepAliveSeconds); executor.setThreadNamePrefix (threadNamePrefix); executor.setRejectedExecutionHandler (new ThreadPoolExecutor.CallerRunsPolicy ()) Executor.initialize (); return executor;}}

The core method of spring async:

The processing is different according to the returned value, which is divided into the following cases:

I heard that the cache is easy to use in National Day holiday, but I didn't expect it to be so easy to use.

Spring cache architecture diagram:

It currently supports multiple caches:

Here we take caffeine as an example, which is officially recommended by spring.

The first step is to introduce the related jar package of caffeine

Org.springframework.boot spring-boot-starter-cache com.github.ben-manes.caffeine caffeine 2.6.0

The second step is to configure CacheManager and enable EnableCaching

@ Configuration @ EnableCaching public class CacheConfig {@ Bean public CacheManager cacheManager () {CaffeineCacheManager cacheManager = new CaffeineCacheManager () / / Caffeine configuration Caffeine caffeine = Caffeine.newBuilder () / / the maximum number of cached entries expired after a fixed time after the last write. MaximumSize (1000); cacheManager.setCaffeine (caffeine); return cacheManager;}}

The third step is to use Cacheable annotations to get data

@ Service public class CategoryService {/ / category is the cache name, and # type is a specific key, which supports the el expression @ Cacheable (value = "category", key = "# type") public CategoryModel getCategory (Integer type) {return getCategoryByType (type);} private CategoryModel getCategoryByType (Integer type) {System.out.println ("get different classification data according to different type:" + type + ")) CategoryModel categoryModel = new CategoryModel (); categoryModel.setId (1L); categoryModel.setParentId (0L); categoryModel.setName ("appliance"); categoryModel.setLevel (3); return categoryModel;}}

When you call the categoryService.getCategory () method, you first get the data from the caffine cache, and if you can get the data, you return it directly without entering the body of the method. If the data is not available, the code in the body of the direct method gets the data and puts it in the caffine cache.

Thank you for your reading, these are the contents of "what are the code skills of Spring?" after the study of this article, I believe you have a deeper understanding of what the code skills of Spring have, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report