Spring IOC -- configuring beans based on annotations
1. Basic use
1. Description
● basic introduction
Beans are configured based on annotations, mainly components in project development, such as Controller, Service, and Dao
● the forms of Component annotation are:
-
@Component indicates that the current annotation identifies a component
-
@Controller indicates that the current annotation identifies a controller, which is usually used for servlets
-
@Service indicates that the current annotation identifies a class that handles business logic, which is usually used for service class
-
@Repository indicates that the current annotation identifies a class of persistence layer, which is usually used for Dao class
2. Quick start
● application examples
Use annotations to configure controller / service / repository / component
● code implementation
- Introduce spring-aop-5.3.8 Jar, which can be copied under spring/libs
- Create useraction java UserService. java, UserDao. java MyComponent. java
/** * It is used to identify that this class is a component and a general annotation */ @Component public class MyComponent { }
/** * Identifies that the class is a controller */ @Controller public class UserController { }
/** * Use @ Repository to identify that the class is a class / object of persistence layer */ @Repository public class UserDao { }
/** * Identity is a Service class */ @Service public class UserService { }
beans.xml
<!-- Configure the packages that the container will scan 1. component-scan To scan the classes under the specified package, And create objects into containers 2. base-package Specifies the package scan to scan com.llp.spring.component Classes under packages and classes under their sub packages 3. The meaning is when spring Container creation/When initialized, it will be scanned com.llp.spring.component package All under are annotated @Controller / @Service / @Respository / @Component class Instantiate it, generate an object, and put it into ioc container 4. resource-pattern="User*.class" Indicates only scan com.llp.spring.component And its sub package User Leading class --> <context:component-scan base-package="com.llp.spring.component"/>
test
/** * Configure bean s by annotation */ @Test public void setBeanByAnnotation(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml"); UserDao userDao = ioc.getBean(UserDao.class); UserService userService = ioc.getBean(UserService.class); UserController userController = ioc.getBean(UserController.class); MyComponent myComponent = ioc.getBean(MyComponent.class); System.out.println(userDao); System.out.println(userService); System.out.println(userController); System.out.println(myComponent); }
3. Precautions and details
1. You need to import spring-aop-5.3.8 jar
2. The "automatically scanned package" must be specified in the Spring configuration file before the IOC container can detect which classes in the current project have been marked with annotations and note the import context namespace
xmlns:context="http://www.springframework.org/schema/context"
<context:component-scan base-package="com.llp.spring.component"/>
You can use wildcard * to specify, such as com llp. spring.* express
Question: com hspedu. spring. Will the component scan its sub packages? it will be
3.Spring's IOC container cannot detect whether a class annotated with @ Controller is a real Controller. The name of the annotation is used by the programmer to identify what component is currently identified.
The same is true for other @ Service and @ Repository [that is, as long as the spring IOC container checks the annotation, it will generate objects, but the meaning of the annotation will not be recognized by spring. The annotation is convenient for programmers to see]
4. Resource pattern = "User*.class": it means that only the classes starting with User are scanned [use less, don't want to scan, don't write notes, just know this knowledge point]
<context:component-scan base-package="com.llp.spring.component" resource-pattern="User*.class"/>
5. What classes are excluded? Take annotation annotation as an example. The following is to exclude @ Service annotation and @ Repository class
<!-- Requirement: if we want to exclude a package/Some type of annotation under the sub package can be exclude-filter To specify 1. context:exclude-filter Specify which classes to exclude 2. type Specify exclusion method annotation Indicates exclusion according to comments 3. expression="org.springframework.stereotype.Service" Specifies the full path of the annotation to exclude(eg: @Service The full class name of the annotation) --> <context:component-scan base-package="com.llp.spring.component"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan>
6. Specify which annotation classes are automatically scanned
<!-- Requirement: if we want to scan the package according to our own rules/Some comments under the sub package, Can pass include-filter 1. use-default-filters="false" Indicates that the default filtering mechanism is not used/scanning mechanism 2. context:include-filter Indicates which classes to scan 3. type="annotation" Scan by annotation/filter 4. expression="org.springframework.stereotype.Service" Specifies the full path of the annotation to scan --> <context:component-scan base-package="com.llp.spring.component" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan>
debug view the value of the table attribute in the SingletonObjects object in beanFactory
7. Default: after the annotation is marked, the first letter of the class name is lowercase as the id value. You can also use the value attribute of the annotation to specify the id value, and value can be omitted. [code demonstration]
/** * Identifies that the class is a controller */ @Controller(value = "user") public class UserController { } /** * Configure bean s by annotation */ @Test public void setBeanByAnnotation(){ ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml"); //When getting the userController, the id becomes the corresponding value value UserService userService = ioc.getBean("user",UserService.class); System.out.println(userController); }
2. Manual development - simple Spring annotation based configuration program
1. Requirements description
- Write a simple Spring container and inject the object into the IOC container by reading the annotation of the class (@ component @ controller @ service @ repository)
- In other words, instead of using Spring's native framework, we use IO + annotation + reflection + collection technology to get through the technical pain points of Spring annotation development
2. Train of thought analysis
-
Thought analysis + program structure
1) We use the annotation method to complete it. Here 2 we don't need xml to configure it
2) Program frame diagram
● application examples
- Manually implement annotation to configure controller / service / repository / component
- We use custom annotations to do this
3. Code implementation
1. Build the basic structure and obtain the scanning package
2. Obtain all information under the scanning package class file
3. Get the full class name and put the reflection object into the container
Custom package scan annotation @ ComponentScan
//Annotation specifies the type of operation @Target(ElementType.TYPE) //Scope of application @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ComponentScan { String value() default ""; }
Configuration class
//The configuration class is similar to our native spring beans XML container configuration file @ComponentScan(value = "com.llp.spring.component") public class LlpSpringConfig { }
Custom container - llspringapplicationcontext
public class LlpSpringApplicationContext { private Class aClass; //ioc I store objects created by reflection (annotation based) private final ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>(); public LlpSpringApplicationContext(Class aClass) { //Pass in llspringconfig this.aClass = aClass; //Get the @ ComponentScan annotation according to the lpspringconfig class ComponentScan componentScan = (ComponentScan) aClass.getDeclaredAnnotation(ComponentScan.class); //Get the package path of @ ComponentScan annotation configuration //basePackage=com.llp.spring.component String basePackage = componentScan.value(); System.out.println("basePackage=" + basePackage); ClassLoader classLoader = LlpSpringApplicationContext.class.getClassLoader(); //path=com/llp/spring/component String path = basePackage.replace(".", "/"); System.out.println("path=" + path); //Obtain the absolute path of the directory according to the package path // file:/C:/ide/IdeaProjects/llp-spring/out/production/llp-spring/com/llp/spring/component URL resource = classLoader.getResource(path); System.out.println(resource); //Get the file directory from the URL object File file = new File(resource.getFile()); //Determine whether the file is a directory if (file.isDirectory()) { //Get all files in the directory File[] files = file.listFiles(); //ergodic for (File f : files) { System.out.println("========="); //Get the absolute path of each file in the directory String absolutePath = f.getAbsolutePath(); //C:\ide\IdeaProjects\llp-spring\out\production\llp-spring\com\llp\spring\component\MyComponent.class System.out.println(f.getAbsolutePath()); //1. Get class name String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf(".class")); System.out.println(className); //2. Get the full class name of the class //com.llp.spring.component String classFullName = path.replace("/", ".") + "." + className; System.out.println(classFullName); //3. Filter and only process the files under the file directory class file if (absolutePath.endsWith(".class")) { //4. Judge whether it needs to be injected into the spirit container to see if the class has annotation @ Component @Service try { //1. Class clazz = Class.forName(classFullName) can reflect loading classes //2. classLoader.loadClass(classFullName); Class that can reflect a class //3. the difference is that the above method is used to call the static method of the class after base note, and the following method will not //4. aClass.isAnnotationPresent(Component.class) determines whether the class has @ Component //Get com llp. spring. Class object of the class under the component package Class<?> cls = classLoader.loadClass(classFullName); //Judge whether there are @ Component, @ Controller, @ Service, @ Repository annotations on this class if (cls.isAnnotationPresent(Component.class) || cls.isAnnotationPresent(Controller.class) || cls.isAnnotationPresent(Service.class) || cls.isAnnotationPresent(Repository.class)) { Class<?> clazz = Class.forName(classFullName); Object o = clazz.newInstance(); String id = null; if(cls.isAnnotationPresent(Component.class)){ Component component = cls.getAnnotation(Component.class); id = component.value(); className = id; } //StringUtils.uncapitalize(className) lowercase the first letter of the class ioc.put(id==null? StringUtils.uncapitalize(className):id,o); System.out.println(ioc); } } catch (Exception e) { e.printStackTrace(); } } } } } public Object getBean(String name){ return ioc.get(name); } }
Test class
public class LlpSpringApplicationContextTest { public static void main(String[] args) { LlpSpringApplicationContext ioc = new LlpSpringApplicationContext(LlpSpringConfig.class); UserService userService = (UserService)ioc.getBean("userService"); UserDao userDao = (UserDao)ioc.getBean("userDao"); UserController userController = (UserController)ioc.getBean("userController"); MyComponent myComponent = (MyComponent)ioc.getBean("myComponent"); } }
test result
3. Automatic assembly
1. Basic description
● basic description
-
Configuring bean s based on annotations can also realize automatic assembly. The annotations used are: @ AutoWired or @ Resource
-
@Description of AutoWired rules
1) Find the type of the component to be assembled in the IOC container. If there is a unique bean matching, the bean assembly will be used
2) If there are multiple bean s corresponding to the type to be assembled in the IOC container, use the attribute name of the attribute to be assembled as the id value and then look it up. If it is found, it will be assembled, and if it is not found, it will throw an exception
-
@Resource rule description
1) Two important attributes of @ Resource are name and type. Spring resolves the name attribute of @ Resource annotation to the name of bean, while the type attribute resolves to the type of bean Therefore, if the name attribute is used, the byName auto injection policy is used, and if the type attribute is used, the byType auto injection policy is used
2) If @ Resource does not specify name and type, byName injection strategy shall be used first. If it fails to match, byType strategy shall be used again. If it fails, an error will be reported
-
It is recommended that both @ Autowired and @ Resource ensure that the attribute name is written in a standard way, so it can be injected
2. Precautions and details
- If there are multiple bean s corresponding to the type to be assembled in the IOC container, use the attribute name of the attribute to be assembled as the id value and then look it up. If it is found, it will be assembled, and if it is not found, it will throw an exception
4. Generic dependency injection
1. Generic dependency interpretation
● basic description
- In order to better manage the automatic assembly of inherited and interdependent bean s, spring also provides an injection mechanism based on generic dependency
- In the case of complex inheritance relationship, generic dependency injection will have great advantages
2. Application examples
● application case requirements
- Relationship diagram of each class
- The traditional method is to automatically assemble PhoneDao /BookDao into bookservice / phoneserve. When there are many inheritance relationships, it is more troublesome. You can use the generic dependency injection provided by spring
● application example - code implementation
//Custom generic classes public abstract class BaseDao<T> { public abstract void save(); }
//Custom generic class public class BaseService<T> { @Autowired private BaseDao<T> baseDao; public void save() { baseDao.save(); } }
public class Book { } public class Phone { } @Repository public class BookDao extends BaseDao<Book>{ @Override public void save() { System.out.println("BookDao of save().."); } } @Repository public class PhoneDao extends BaseDao<Phone>{ @Override public void save() { System.out.println("PhoneDao save()"); } } @Service public class BookService extends BaseService<Book>{ //No write attribute } @Service public class PhoneService extends BaseService<Phone>{ }
//Configuring beans through generic dependencies @Test public void setProByDependencyInjection() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans07.xml"); PhoneService phoneService = ioc.getBean("phoneService", PhoneService.class); phoneService.save(); System.out.println("ok"); }