spring基础
依赖查找:
BeanFactory beanFactory = new ClassPathXmlApplicationContext("basic_di/inject-set.xml");
Person person = beanFactory.getBean(Person.class);
根据type查找一组对象:
ApplicationContext ctx = new ClassPathXmlApplicationContext("basic_dl/quickstart-oftype.xml");
Map<String, DemoDao> beans = ctx.getBeansOfType(DemoDao.class);
beans.forEach((beanName, bean) -> {
System.out.println(beanName + " : " + bean.toString());
});
根据注解查找:
ApplicationContext 中有一个方法叫 getBeansWithAnnotation ,它可以传入一个注解的 class ,返回所有被这个注解标注的 bean 。
ApplicationContext ctx = new ClassPathXmlApplicationContext("basic_dl/quickstart-withanno.xml");
Map<String, Object> beans = ctx.getBeansWithAnnotation(Color.class);
beans.forEach((beanName, bean) -> {
System.out.println(beanName + " : " + bean.toString());
});
获取IOC容器中的所有Bean:ApplicationContext的getBeanDefinitionNames()方法
ApplicationContext ctx = new ClassPathXmlApplicationContext("basic_dl/quickstart-withanno.xml");
String[] beanNames = ctx.getBeanDefinitionNames();
// 利用jdk8的Stream快速编写打印方法
Stream.of(beanNames).forEach(System.out::println);
查找是否有某个bean:ApplicationContext.containsBean()
延迟查找:ApplicationContext.getBeanProvider()
ObjectProvider<Dog> dogProvider = ctx.getBeanProvider(Dog.class);
Dog dog = dogProvider.getIfAvailable();
if (dog == null) {
dog = new Dog();
}
//或者
Dog dog = dogProvider.getIfAvailable(() -> new Dog());
依赖注入: property注入, value直接赋值,ref引用
<bean id="person" class="com.linkedbear.spring.basic_di.a_quickstart_set.bean.Person">
<property name="name" value="test-person-byset"/>
<property name="age" value="18"/>
</bean>
<bean id="cat" class="com.linkedbear.spring.basic_di.a_quickstart_set.bean.Cat">
<property name="name" value="test-cat"/>
<!-- ref引用上面的person对象 -->
<property name="master" ref="person"/>
</bean>
setter属性注入:
// xml:
<bean id="person" class="com.linkedbear.spring.basic_di.a_quickstart_set.bean.Person">
<property name="name" value="test-person-byset"/>
<property name="age" value="18"/>
</bean>
// 注解:
@Bean
public Person person() {
Person person = new Person();
person.setName("test-person-anno-byset");
person.setAge(18);
return person;
}
构造器注入:
//xml
<bean id="person" class="com.linkedbear.spring.basic_di.b_constructor.bean.Person">
<constructor-arg index="0" value="test-person-byconstructor"/>
<constructor-arg index="1" value="18"/>
</bean>
//注解
@Bean
public Person person() {
return new Person("test-person-anno-byconstructor", 18);
}
@Component下的属性注入:
@Value("black-value-anno")
private String name;
//外部引入:从.properties文件中引入
@Configuration
@ComponentScan("com.linkedbear.spring.basic_di.c_value_spel.bean")
@PropertySource("classpath:basic_di/value/red.properties")
public class InjectValueConfiguration {
}
@Value("${red.name}")
private String name;
//xml中
<bean class="com.linkedbear.spring.basic_di.c_value_spel.bean.Red">
<property name="name" value="${red.name}"/>
<property name="order" value="${red.order}"/>
</bean>
自动注入:@Autowired
//1
@Autowired
private Person person;
//2
@Autowired
public Dog(Person person) {
this.person = person;
}
//3
@Autowired
public void setPerson(Person person) {
this.person = person;
}
//4
@Bean
@Autowired // 高版本可不标注
public Cat cat(Person person) {
Cat cat = new Cat();
cat.setName("mimi");
cat.setPerson(person);
return cat;
}
存在多个同类型的bean时,使用@Autowired会报错:
1.使用@Qualifier显示指定bean的id
2.@Primary标记优先的bean
3.修改变量名,与bean的id对应
//1
@Autowired
@Qualifier("administrator")
private Person person;
//2
@Bean
@Primary
public Person master() {
Person master = new Person();
master.setName("master");
return master;
}
//3
@Autowired
private Person administrator;
@Autowired注入的原理逻辑:
先拿属性对应的类型,去 IOC 容器中找 Bean ,如果找到了一个,直接返回;如果找到多个类型一样的 Bean , 把属性名拿过去,跟这些 Bean 的 id 逐个对比,如果有一个相同的,直接返回;如果没有任何相同的 id 与要注入的属性名相同,则会抛出 NoUniqueBeanDefinitionException 异常。
注入一组对象:
@Autowired
private List<Person> persons;
@Resource注解:按属性名注入 (先按名字注入,没写就是属性名,找不到name再按type注入)
@Resource(name = "master")
private Person person;
注解驱动:AnnotationConfigApplicationContext
@Bean(name = "aaa") // 4.3.3之后可以直接写value,name就是id,不写的话是方法名作为id
public Person person() {
return new Person();
}
@Component("aaa") //模式注解,不指定的话id就是类名小写
public class Person { }
ApplicationContext ctx = new AnnotationConfigApplicationContext(QuickstartConfiguration.class); //可以传入配置类,也可以传入根包
Person person = ctx.getBean(Person.class);
System.out.println(person);
@ComponentScan:搭配@Configuration一起用,扫描指定路径包及子包下的所有 @Component 组件;如果不指定扫描路径,则默认扫描本类所在包及子包下的所有 @Component 组件。
AnnotationConfigApplicationContext 的构造方法中有一个类型为 String 可变参数的构造方法:可以扫描对应包下的@component组件
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.linkedbear.spring.annotation.c_scan.bean");
xml中启用组件扫描:
<context:component-scan base-package="com.linkedbear.spring.annotation.c_scan.bean"/>
@Configuration也是@Component
xml中引入注解:在 xml 中要引入注解配置,需要开启注解配置,同时注册对应的配置类
<context:annotation-config />
<bean class="com.linkedbear.spring.annotation.d_importxml.config.AnnotationConfigConfiguration"/>
注解引入xml:在注解配置中引入 xml ,需要在配置类上标注 @ImportResource 注解,并声明配置文件的路径:
@Configuration
@ImportResource("classpath:annotation/beans.xml")
public class ImportXmlAnnotationConfiguration {
}
bean的类型与作用域:
类型分为普通bean和工厂bean,作用域分为单例,原型,request,session,application,websocket
factorybean:
public interface FactoryBean<T> {
// 返回创建的对象
@Nullable
T getObject() throws Exception;
// 返回创建的对象的类型(即泛型类型)
@Nullable
Class<?> getObjectType();
// 创建的对象是单实例Bean还是原型Bean,默认单实例
default boolean isSingleton() {
return true;
}
}
public class ToyFactoryBean implements FactoryBean<Toy> {
private Child child;
@Override
public Toy getObject() throws Exception {
switch (child.getWantToy()) {
case "ball":
return new Ball("ball");
case "car":
return new Car("car");
default:
// SpringFramework2.0开始允许返回null
// 之前的1.x版本是不允许的
return null;
}
}
@Override
public Class<Toy> getObjectType() {
return Toy.class;
}
public void setChild(Child child) {
this.child = child;
}
}
@Bean
public Child child() {
return new Child();
}
@Bean
public ToyFactoryBean toyFactory() {
ToyFactoryBean toyFactory = new ToyFactoryBean();
toyFactory.setChild(child());
return toyFactory;
}
factoryBean的创建时机:FactoryBean是在IOC初始化时创建的,FactoryBean 生产 Bean 的机制是延迟生产。
作用域与创建时机:@Scope(),singlieton的创建时机为IOC容器创建时,property的创建时机为getbean时
request:请求Bean,每次客户端向 Web 应用服务器发起一次请求,Web 服务器接收到请求后,由 SpringFramework 生成一个 Bean ,直到请求结束
session :会话Bean,每个客户端在与 Web 应用服务器发起会话后,SpringFramework 会为之生成一个 Bean ,直到会话过期
application :应用Bean,每个 Web 应用在启动时,SpringFramework 会生成一个 Bean ,直到应用停止(有的也叫 global-session )
websocket :WebSocket Bean ,每个客户端在与 Web 应用服务器建立 WebSocket 长连接时,SpringFramework 会为之生成一个 Bean ,直到断开连接
静态工厂创建bean:静态工厂本身不会被注册到 IOC 容器中
public class CarStaticFactory {
public static Car getCar() {
return new Car();
}
}
<bean id="car2" class="com.linkedbear.spring.bean.c_instantiate.bean.CarStaticFactory" factory-method="getCar"/>
//编程式
@Bean
public Car car2() {
return CarStaticFactory.getCar();
}
实例工厂创建bean:
public class CarInstanceFactory {
public Car getCar() {
return new Car();
}
}
<bean id="carInstanceFactory" class="com.linkedbear.spring.bean.c_instantiate.bean.CarInstanceFactory"/> //先创建示例工厂
<bean id="car3" factory-bean="carInstanceFactory" factory-method="getCar"/> //再用实例工厂创建bean
//编程式
@Bean
public Car car3(CarInstanceFactory carInstanceFactory) {
return carInstanceFactory.getCar();
}
bean的生命周期:
实例化-初始化-运行-销毁-垃圾回收
可干预阶段:初始化与销毁
init-method&destroy-method:在 IOC 容器初始化之前,默认情况下 Bean 已经创建好了,而且完成了初始化动作;容器调用销毁动作时,先销毁所有 Bean ,最后 IOC 容器全部销毁完成。bean的生命周期中,先对属性赋值,再执行init-method 标记的方法。原型bean的生命周期与IOC容器无关
public class Cat {
private String name;
public void setName(String name) {
this.name = name;
}
public void init() {
System.out.println(name + "被初始化了。。。");
}
public void destroy() {
System.out.println(name + "被销毁了。。。");
}
}
//xml
<bean class="com.linkedbear.spring.lifecycle.a_initmethod.bean.Cat"
init-method="init" destroy-method="destroy">
<property name="name" value="mimi"/>
//编程式
@Bean(initMethod = "init", destroyMethod = "destroy")
public Dog dog() {
Dog dog = new Dog();
dog.setName("wangwang");
return dog;
}
对于@Compoment创建的bean,使用@PostConstruct 、@PreDestroy 来对应 init-method 和 destroy-method 。
@Component
public class Pen {
private Integer ink;
@PostConstruct
public void addInk() {
System.out.println("钢笔中已加满墨水。。。");
this.ink = 100;
}
@PreDestroy
public void outwellInk() {
System.out.println("钢笔中的墨水都放干净了。。。");
this.ink = 0;
}
@Override
public String toString() {
return "Pen{" + "ink=" + ink + '}';
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)