引入maven
的坐标:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.16</version>
</dependency>
新建com.enjoy.cap1
包,在其底下新键一个Person
类
package com.enjoy.cap1;
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
基于配置文件(不推荐)
在resources
底下新建xml文件,名为beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.enjoy.cap1.Person">
<!-- 需要提供无参构造 -->
<property name="name" value="godX"></property>
<property name="age" value="22"></property>
</bean>
</beans>
在com.enjoy.cap1
包下新建测试类MainTest1
进行测试
package com.enjoy.cap1;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
/* IOC容器相当于一个很大的map */
Person p = (Person)app.getBean("person");
System.out.println(p);
}
}
基于注解(推荐)
在com.enjoy.cap1
包下新建包config
,并在其底下新建一个类MainConfig
package com.enjoy.cap1.config;
import com.enjoy.cap1.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//配置类=配置文件
@Configuration
public class MainConfig {
//给容器中注册一个bean,类型为返回值类型 id为方法名
//@Bean(name = "aa")可以手动指定id
@Bean
public Person person(){
return new Person("godY",22);
}
}
在com.enjoy.cap1
包下新建测试类MainTest2
进行测试
package com.enjoy.cap1;
import com.enjoy.cap1.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainTest2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
/* IOC容器相当于一个很大的map */
Person p = (Person)app.getBean("person");
System.out.println(p);
//获取所有的bean的id
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
输出结果:
Person{name='godY', age=22}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
id为person的bean是在配置类里面创建的,在配置文件中,可以手动指定id的名字。在配置类中,不指定id的名字,则默认为方法名
。
这两种解析方式的类继承结构图如下:
@ComponentScan
在com.enjoy.cap2
包下操作
新建config
包,在其底下新建类Cap2MainConfig
package com.enjoy.cap2.config;
import com.enjoy.cap1.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(value = "com.enjoy.cap2")
public class Cap2MainConfig {
@Bean
public Person person(){
return new Person("godY",22);
}
}
新建controller
包,在其底下新建类OrderController
package com.enjoy.cap2.controller;
import org.springframework.stereotype.Controller;
@Controller
public class OrderController {
}
新建dao
包,在其底下新建类OrderDao
package com.enjoy.cap2.dao;
import org.springframework.stereotype.Repository;
@Repository
public class OrderDao {
}
新建service
包,在其底下新建类OrderService
package com.enjoy.cap2.service;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
}
新建测试类Cap2MainTest1
package com.enjoy.cap2;
import com.enjoy.cap2.config.Cap2MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Cap2MainTest1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
输出
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
orderController
orderDao
orderService
person
ComponentScan注解的重要属性
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
//写basePackages或者写value,效果是一样的
@AliasFor("basePackages")
String[] value() default {};
//写basePackages或者写value,效果是一样的
@AliasFor("value")
String[] basePackages() default {};
//自定义扫描规则
ComponentScan.Filter[] includeFilters() default {};
//自定义扫描规则
ComponentScan.Filter[] excludeFilters() default {};
//是否使用其默认的扫描规则
boolean useDefaultFilters() default true;
//和自定义扫描规则配合使用,过滤器
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
自定义扫描规则的使用
ANNOTATION
package com.enjoy.cap2.config;
import com.enjoy.cap1.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@Configuration
//只扫描Controller注解,需要将默认的扫描规则关掉(不然其他注解修饰的类还是会被注入进来)
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
public class Cap2MainConfig {
@Bean
public Person person(){
return new Person("godY",22);
}
}
输出
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
orderController
person
package com.enjoy.cap2.config;
import com.enjoy.cap1.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@Configuration
//排除Controller注解,需要将默认的扫描规则开启(不然不知道扫描谁)
@ComponentScan(value = "com.enjoy.cap2",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = true)
public class Cap2MainConfig {
@Bean
public Person person(){
return new Person("godY",22);
}
}
输出
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
orderDao
orderService
person
ASSIGNABLE_TYPE
package com.enjoy.cap2.config;
import com.enjoy.cap1.Person;
import com.enjoy.cap2.controller.OrderController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {OrderController.class})
},useDefaultFilters = false)
public class Cap2MainConfig {
@Bean
public Person person(){
return new Person("godY",22);
}
}
输出
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
orderController
person
CUSTOM
在config
包下新建类TypeFilter
package com.enjoy.cap2.config;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import java.io.IOException;
public class TypeFilter implements org.springframework.core.type.filter.TypeFilter {
/**
*
* @param metadataReader 读取到当前正在扫描的类的信息,
* @param metadataReaderFactory 可以获取到其他类的信息
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotationMetadata annos = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取类路径
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println(className);
return false;
}
}
配置类修改:
package com.enjoy.cap2.config;
import com.enjoy.cap1.Person;
import com.enjoy.cap2.controller.OrderController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {TypeFilter.class})
},useDefaultFilters = false)
public class Cap2MainConfig {
@Bean
public Person person(){
return new Person("godY",22);
}
}
输出:
com.enjoy.cap2.Cap2MainTest1
com.enjoy.cap2.config.TypeFilter
com.enjoy.cap2.controller.OrderController
com.enjoy.cap2.dao.OrderDao
com.enjoy.cap2.service.OrderService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
person
修改自定义过滤器
package com.enjoy.cap2.config;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import java.io.IOException;
import java.lang.annotation.Annotation;
public class TypeFilter implements org.springframework.core.type.filter.TypeFilter {
/**
*
* @param metadataReader 读取到当前正在扫描的类的信息,
* @param metadataReaderFactory 可以获取到其他类的信息
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotationMetadata annos = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取类路径
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
if (annos.hasAnnotation("org.springframework.stereotype.Controller"))return true;
return false;
}
}
输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
orderController
person
@Scope
确定其是单实例还是多实例
多实例:仅当bean被使用
的时候才创建
单实例:创建IOC容器的时候
实例bean就被创建 默认
cap3
包下操作
config
包下新建类Cap3MainConfig
package com.enjoy.cap3.config;
import com.enjoy.cap1.Person;
import com.enjoy.cap2.config.TypeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
public class Cap3MainConfig {
@Bean
public Person person(){
return new Person("godY",22);
}
}
测试类
package com.enjoy.cap3;
import com.enjoy.cap1.Person;
import com.enjoy.cap3.config.Cap3MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Cap3MainTest1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
//证明@Bean方式注入是单实例
Person p = (Person)app.getBean("person");
Person p1 = (Person)app.getBean("person");
System.out.println(p == p1);
}
}
输出:
true
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
//PROTOTYPE多实例 SINGLETON单实例
@AliasFor("scopeName")
String value() default "";
@AliasFor("value")
String scopeName() default "";
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
修改配置类
package com.enjoy.cap3.config;
import com.enjoy.cap1.Person;
import com.enjoy.cap2.config.TypeFilter;
import org.springframework.context.annotation.*;
@Configuration
public class Cap3MainConfig {
//singleton
@Scope(value = "prototype")
@Bean
public Person person(){
return new Person("godY",22);
}
}
输出
false
创建时机的证明
切换成单实例,在Person
类的有参构造加一个输出,测试修改为:
package com.enjoy.cap3;
import com.enjoy.cap1.Person;
import com.enjoy.cap3.config.Cap3MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Cap3MainTest1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
//证明@Bean是单实例
/*Person p = (Person)app.getBean("person");
Person p1 = (Person)app.getBean("person");
System.out.println(p == p1);*/
}
}
输出:
被创建
切换成多实例
无输出
拓展
Scopr取值为request
一次请求一个实例,session
一次会话一个实例。[针对web]
@Lazy懒加载
针对单实例bean
容器启动的时候不创建对象,仅当第一次使用的时候才创建
在cap4
包下操作
config
包下,Cap4MainConfig
类
package com.enjoy.cap4.config;
import com.enjoy.cap1.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
@Configuration
public class Cap4MainConfig {
@Lazy
@Bean
public Person person(){
return new Person("godY",22);
}
}
Cap4MainTest1
类
package com.enjoy.cap4;
import com.enjoy.cap4.config.Cap4MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Cap4MainTest1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap4MainConfig.class);
System.out.println("IOC容器完成");
Object p = app.getBean("person");
}
}
输出
IOC容器完成
被创建
给@Lazy
注释掉
输出
被创建
IOC容器完成