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

How to hand over dynamic proxy objects to Spring container management

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

Share

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

It is believed that many inexperienced people do not know what to do about how to manage dynamic proxy objects by Spring containers. Therefore, this paper summarizes the causes and solutions of the problems. Through this article, I hope you can solve this problem.

1. The instantiation process of spring bean

In our daily development, if we want to inject the instance object of the class into the ioc container, we only need to add the corresponding annotations to the class. Commonly used are @ Controller,@Service,@Component and other annotations, so they are all used in this way, but the principle is not understood. Let's go through the loading process of spring bean.

How to describe a bean in ① spring

At this point, let's take a look at how an instance in java is described.

In java, what properties and methods an object has are defined in the class that describes the object instance through the class. Then it is mutated into a class bytecode file, and an instance object can be obtained through the new keyword.

So how does the bean in spring describe it?

The first part is the same, registered in beanDefinition through Registrar, and the beanDefinition object is used in spring to describe the object to be instantiated, including the name of the bean, class, whether it is abstract, whether it is a singleton, and other information, and then instantiated to the ioc container through preInstantiateSingletons. When we want to use the object, we can get the corresponding object from the ioc container.

In the process of instantiating spring bean, spring designs many interception points, which can dynamically change the relevant information of the instantiated object. The object in the ioc container is different from the information originally registered in the beanDefinition.

2. FactoryBean

Now let's take a look at FactoryBean. FactoryBean ends with bean in terms of its name, which should be a bean. Yes, it is indeed a bean. Unlike ordinary Bean, it is a Bean that implements the FactoryBean interface.

Special properties:

According to the ID of the Bean, what is actually obtained from the BeanFactory is the object returned by the getObject () of the FactoryBean, not the FactoryBean itself. If you want to get the FactoryBean object, add a & symbol before the id to get it.

Public interface FactoryBean {/ / get the instance object corresponding to bean @ Nullable T getObject () throws Exception; / / obtain the instance type @ Nullable Class getObjectType () obtained by factoryBean; / / whether the instance created by FactoryBean is a single instance default boolean isSingleton () {return true;}}

Let's verify the special nature of this FactoryBean by customizing a bean. Prepare a test bean first

Public class TestBean {}

Write a custom FactoryBean

Component ("myFactoryBean") public class MyFactoryBean implements FactoryBean {@ Override public Object getObject () throws Exception {return new TestBean ();} @ Override public Class getObjectType () {return TestBean.class;}}

Write test classes. Get the myFactoryBean instance from the springioc container.

Object bean = SpringContextUtils.getBean ("myFactoryBean"); System.out.println (bean); / / com.wj.factorybean.TestBean@2d459bdaObject bean = SpringContextUtils.getBean ("& myFactoryBean"); System.out.println (bean); / / com.wj.factorybean.MyFactoryBean@60ab895f

The above properties are verified by seeing the printing results.

3. BeanFactoryPostProcessor

BeanFactoryPostProcessor can update some properties of the original beanDefinition before the object is instantiated to the ioc container.

Let's take a look at the example. Prepare to connect bean, in which TestBean we @ omponent annotation, but TestBean1 does not do processing

Component ("testBean") public class TestBean {} public class TestBean1 {}

Write BeanFactoryPostProcessor implementation classes

@ Componentpublic class MyFactoryPostProcessor implements BeanFactoryPostProcessor {@ Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException {/ / get beanDefinition GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition ("testBean") of testBean; / / change class to TestBean1 beanDefinition.setBeanClass (TestBean1.class);}}

Write test classes for testing

Object bean = SpringContextUtils.getBean ("testBean"); / / com.wj.factorybean.TestBean1@45dc7beSystem.out.println (bean)

I clearly got an instance of testBean, and all I got was an instance of TestBean1. This shows that we changed the object before it was instantiated through BeanFactoryPostProcessor. So what we got is TestBean1. With BeanFactoryPostProcessor, we can tamper with the object to be instantiated before it is instantiated into the ioc container. But this is just an update. So we have to register the object with BeanDefinition manually. The following ImportBeanDefinitionRegistrar will be useful.

4. ImportBeanDefinitionRegistrar

It seems that so much has been said, but it is not related to today's topic. The dynamic proxy object is not mentioned at all. There's no hurry. I'll be back in a minute. We're getting closer to the topic step by step.

ImportBeanDefinitionRegistrar can dynamically register its own objects with BeanDefinition, and then spring's bean instantiates the process to generate instance objects to the ioc container.

Write a test Dao interface, why an interface? Because we are going to use proxies to generate instance objects of Dao.

Public interface MyDao {void query ();}

Write a custom Registrar

Public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@ Override public void registerBeanDefinitions (AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {here we use the previously defined MyFactoryBean BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition (MyFactoryBean.class); / / generate beanDefinition GenericBeanDefinition beanDefinition = (GenericBeanDefinition) builder.getBeanDefinition (); / / register beanDefinition as beanDefinitionRegistry.registerBeanDefinition (MyDao.class.getName (), beanDefinition);}}

Change MyFactoryBean to generate interface MyDao object by dynamic proxy

Public class MyFactoryBean implements FactoryBean {@ Override public Object getObject () throws Exception {/ / generate MyDao instance object Object instance = Proxy.newProxyInstance (MyFactoryBean.class.getClassLoader (), new Class [] {MyDao.class}, new InvocationHandler () {@ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {System.out.println ("execute business logic") Return null;}}); return instance;} @ Override public Class getObjectType () {return MyDao.class;}}

Customize the annotation @ MyScan and import MyImportBeanDefinitionRegistrar through @ Import. So it will be scanned by spring.

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

As a final step, add @ MyScan to the project startup class. And write tests. Call Mydao

MyDao myDao = SpringContextUtils.getBean (MyDao.class); myDao.execute (); / / print out "execute business logic"

At this point, we leave the dynamic proxy classes to ioc to manage.

5. Simply simulate the dynamic proxy Mapper interface in Mybaitis to execute sql

Let's extend it. Don't we have a MyDao? And the proxy implementation in MyFactoryBean is also hard-coded. MyImportBeanDefinitionRegistrar is also written dead, this is not possible, so how do we write it alive?

Define variables in MyFactoryBean to accept class and set the value through the constructor. The final modified MyFactoryBean is as follows

Public class MyFactoryBean implements FactoryBean {private Class classzz; public MyFactoryBean (Class classzz) {this.classzz = classzz } @ Override public Object getObject () throws Exception {/ / generate instance object Object instance = Proxy.newProxyInstance (MyFactoryBean.class.getClassLoader (), new Class [] {classzz.class}, new InvocationHandler () {@ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {System.out.println ("execute business logic") Return null;}}); return instance;} @ Override public Class getObjectType () {return this.classzz;}}

To change the MyImportBeanDefinitionRegistrar logic, we define a Class data to simulate multiple class. Generate MyFactoryBean through beanDefinition.getConstructorArgumentValues (). AddGenericArgumentValue (aClass.getTypeName ()); call the parameterized constructor of MyFactoryBean.

Public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@ Override public void registerBeanDefinitions (AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {/ / the array is written dead here. We can define a package and scan all the interfaces under the package class. We will not implement it here. In order to demonstrate the effect, an additional interface MyDao1 is defined. If the definition is the same as MyDao, the code will not be posted. Class [] classes = {MyDao.class,MyDao1.class}; for (Class aClass: classes) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition (MyFactoryBean.class); GenericBeanDefinition beanDefinition = (GenericBeanDefinition) builder.getBeanDefinition (); / / call the MyFactoryBean parameter constructor beanDefinition.getConstructorArgumentValues (). AddGenericArgumentValue (aClass.getTypeName ()); beanDefinitionRegistry.registerBeanDefinition (aClass.getName (), beanDefinition) }}}

Test example

MyDao myDao = SpringContextUtils.getBean (MyDao.class); myDao.query (); / / execute business logic MyDao1 myDao1 = SpringContextUtils.getBean (MyDao1.class); myDao1.query (); / / execute business logic

Do you feel a bit like mybatis, interface Mapper, without any implementation, but can be directly called @ Autowired, yes, it is simulating Mybatis. However, we define the @ MyScan annotation, which is the @ MapperScan annotation, followed by the package path of Mapper, so we don't implement the class here, because we define an array in MyImportBeanDefinitionRegistrar to simulate the package path scan class. To refine it, we call a Dao that executes the same logic. Different sql queries should be executed. Let's make that happen.

Customize the @ Select annotation, which is used on the definition of Dao interface method. Value is the sql statement.

@ Target (ElementType.METHOD) @ Retention (RetentionPolicy.RUNTIME) @ Documentedpublic @ interface Select {String value () default "";}

Use @ Select annotations in the Dao interface

Public interface MyDao {@ Select ("SELECT * FROM T1") void query ();} public interface MyDao1 {@ Select ("SELECT * FROM T2") void query ();}

The concrete sql logic is written in the InvocationHandler where the dynamic proxy generates the proxy object.

Public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {String value = method.getDeclaredAnnotation (Select.class) .value (); System.out.println (value); return null;}

Call the test method you just did, and print the sql statement.

MyDao myDao = SpringContextUtils.getBean (MyDao.class); myDao.query (); / / SELECT * FROM T1MyDao1 myDao1 = SpringContextUtils.getBean (MyDao1.class); myDao1.query (); / / SELECT * FROM T26. Summary

Spring is really good at high scalability, and third-party plug-ins can implement different interfaces to extend spring. It's like integrating Mybatis into Spring. In our daily development, in order to meet the ever-changing requirements, it is very necessary to design programs that are easy to expand. Blindly according to the demand to achieve hard-coding, behind the business changes, only overtime, and then change every day, their own technology is also limited. Being dragged by the product all day. Working overtime every day, time is spent on repetitive work, which is not good for your growth.

After reading the above, have you learned how to leave dynamic proxy objects managed by Spring containers? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

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

Internet Technology

Wechat

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

12
Report