基于Spring4的Bean的装配和依赖注入

本文详细介绍了Spring框架中Bean的装配方式与依赖注入的方法,包括基于注解的Bean管理、不同实例化Bean的方式及Bean生命周期的自定义处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于准备着手研究一下Spring BootSpring Cloud,所以抽空把Spring对Bean的装配和Spring容器的依赖注入重新整理了一下,理解了一下内在本质!


今天主要整理的是基于注解的方式对Bean的管理,下面是具体的Demo!


Maven依赖:

		<!-- Spring Context 依赖 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.9.RELEASE</version>
		</dependency>

		<!-- JSR 330 依赖 -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>

Demo01:

		//通过加入组建
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class, User.class, UserDao.class,UserService.class,UserController.class);
		//通过扫描包
		//AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.harry.**");

注: 首先获取Spring容器applicationContext,这里通过添加配置类组建的方式或者扫描包的方式来让Spring对Bean进行装配,接着通过容器才对Bean进行一系列操作。


MyConfig.Java

package com.harry.spring4.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;

/**
 * Bean的配置类,类似于applicationContext.xml里配置的各种Bean
 * 
 * @author Harry Wan
 *
 */
@Configuration
public class MyConfig {

	/**
	 * 表示配置了一个Bean,name默认为方法名 "createMyBean"
	 * 
	 * @return
	 */
	@Bean
	@Scope(scopeName = "prototype")
	public MyBean createMyBean() {
		return new MyBean();
	}

	/**
	 * 自定义Bean的name,从容器中获取时按定义的名称获取
	 * 
	 * @return
	 */
	@Bean(name = "myBean")
	@Scope(scopeName = "prototype")
	public MyBean createMyBeanWithRename() {
		return new MyBean();
	}

	@Bean
	public MyFactoryBean createMyFactoryBean() {
		return new MyFactoryBean();
	}

	@Bean
	public MyCustomFactory createMyCustomFactory() {
		return new MyCustomFactory();
	}

	@Bean
	public MyBean createMyBeanByCustomFactory(MyCustomFactory factory) {
		return factory.createMyBean();
	}

	@Bean
	public MyBean2 createMyBean2ByCustomFactory(MyCustomFactory factory) {
		return factory.createMyBean2();
	}

	@Bean
	public MyBean3 createMyBean3() {
		return new MyBean3();
	}
	
	@Bean(initMethod = "init", destroyMethod = "destroy")
	public MyBean4 createMyBean4() {
		return new MyBean4();
	}
	
	@Bean
	public MyBean5 createMyBean5() {
		return new MyBean5();
	}
	
	@Bean
	//@Primary
	public UserDao createUserDao(){
		return new UserDao();
	}
	
}


注: 这里通过@Configuration注解表示当前为配置类,类似于项目中的applicationContext.xml,同时通过@Bean来标识自定义实例化的Bean


实例化Bean的四种方式:

第一种:
		/**第一种方式: 通过自定义创建实例化Bean,交给Spring来管理**/
		//从容器中通过类型来获取. 
		//注: 若容器中有多个实例化Bean的方法,此时通过类型来获取,会Bean匹配错误
		//System.out.println(applicationContext.getBean(MyBean.class));
		
		//从容器中通过名称来获取
		System.out.println(applicationContext.getBean("createMyBean"));
		System.out.println(applicationContext.getBean("myBean"));

配置:

/**
	 * 表示配置了一个Bean,name默认为方法名 "createMyBean"
	 * 
	 * @return
	 */
	@Bean
	@Scope(scopeName = "prototype")
	public MyBean createMyBean() {
		return new MyBean();
	}

	/**
	 * 自定义Bean的name,从容器中获取时按定义的名称获取
	 * 
	 * @return
	 */
	@Bean(name = "myBean")
	@Scope(scopeName = "prototype")
	public MyBean createMyBeanWithRename() {
		return new MyBean();
	}


注:在配置类中自定义实例化Bean方法,并且使用@Bean注解标识,交给Spring管理,最后通过容器获取Bean实例.在通过类型获取时,如果在容器中有多个实例化Bean的方法,Spring会报匹配错误,在通过名称获取时,如果不自定义@Bean(name = "myBean"),默认的名称为实例化Bean的方法名applicationContext.getBean("createMyBean")

第二种:

		/** 第二种方式: 通过BeanFactory来创建实例化Bean**/
		//通过类型获取FactoryBean创建的Bean的实例对象
		//System.out.println(applicationContext.getBean(MyBean2.class));
		//通过名字来获取FactoryBean创建的Bean的实例对象
		System.out.println(applicationContext.getBean("createMyFactoryBean"));
		
		//通过类型获取到的是MyFactoryBean本身,并非MyFactoryBean创建出来的Bean
		System.out.println(applicationContext.getBean(MyFactoryBean.class));
		//通过名称获取到的是MyFactoryBean本身,并非MyFactoryBean创建出来的Bean
		System.out.println(applicationContext.getBean("&createMyFactoryBean"));

MyFactoryBean.java
package com.harry.spring4.demo;

import org.springframework.beans.factory.FactoryBean;
/**
 * 通过FactoryBean 来创建对象
 * @author Harry Wan
 *
 */
public class MyFactoryBean implements FactoryBean<MyBean2> {
	
	//获取到FactoryBean所创建的实力对象
	public MyBean2 getObject() throws Exception {
		return new MyBean2();
	}
	
	//获取Bean的类型
	public Class<?> getObjectType() {
		return MyBean2.class;
	}

	public boolean isSingleton() {
		return true;
	}

}


注:这里通过实现FactoryBean接口传入需要实例化的Bean类型,实现对应的方法,再将我们自定义的MyFactoryBean添加到配置类中,最终来获取我们需要实例化的Bean对象。
由于FactoryBean也可以抽象成Bean的一种,所以在获取时要区分我们需要的目标Bean对象和FactoryBean对象


第三种:

		/** 第三种方式: 通过自定义Factory来创建Bean实例,把自定义的Factory也当作Bean交给Spring来管理 **/
		//可以通过类型来获取MyBean.class,为了避免通过类型匹配到多个实例化Bean的方法,改为通过Name来获取
		System.out.println(applicationContext.getBean("createMyBeanByCustomFactory"));
		System.out.println(applicationContext.getBean("createMyBean2ByCustomFactory"));

自定义实例化Bean的工厂类MyCustomFactory.java:

package com.harry.spring4.demo;

public class MyCustomFactory {
	
	public MyBean createMyBean() {
		return new MyBean();
	}
	
	public MyBean2 createMyBean2() {
		return new MyBean2();
	}
}


配置类MyConfig.java:

	@Bean
	public MyCustomFactory createMyCustomFactory() {
		return new MyCustomFactory();
	}

	@Bean
	public MyBean createMyBeanByCustomFactory(MyCustomFactory factory) {
		return factory.createMyBean();
	}

	@Bean
	public MyBean2 createMyBean2ByCustomFactory(MyCustomFactory factory) {
		return factory.createMyBean2();
	}

注: 这里将自定义Bean的工厂类加入到Spring容器中进行管理,在实例化目标Bean时,对于需要的工厂类参数,Spring会自动去匹配当前容器中已经装配好的对应工厂对象进行传入


第四种:

		/**第四种方式: 通过使用@Component组件相关注解,交给Spring容器装配**/
		//注: 实际开发中通常使用scan扫描包自动加入Spring容器(new AnnotationConfigApplicationContext("com.harry.**");),如若其他方式要手动加入到Spring容器中
		System.out.println(applicationContext.getBeansOfType(User.class));//获取Spring容器管理Bean时该Bean使用的默认名称(Map: 名称 = 实例化对象)
		//@Component
		System.out.println(applicationContext.getBean(User.class));
		System.out.println(applicationContext.getBean("myUser"));
		//@Repository
		System.out.println(applicationContext.getBean(UserDao.class));
		//@Service
		System.out.println(applicationContext.getBean(UserService.class));
		//@Controller
		System.out.println(applicationContext.getBean(UserController.class));
注:通过使用@Component等注解表示当前类为Spring的组建,Spring默认进行装配进行管理,这也是实际开发中用的最多的方式




//---------------------------------------------------------这是一道华丽的分界线------------------------------------------------------

实现Bean在被Spring容器加载之后和被销毁之后自定义添加业务逻辑的三种方式


第一种:

/**第一种方式: 目标Bean实现InitializingBean, DisposableBean接口,实现对应的afterPropertiesSet()和destroy()方法**/
		System.out.println(applicationContext.getBean("createMyBean3"));

package com.harry.spring4.demo;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class MyBean3 implements InitializingBean, DisposableBean {
	
	/**
	 * 当Bean被Spring加载之后会执行
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("==It will be executed after being Loaded==");
	}
	
	/**
	 * 当Bean销毁之后会执行
	 */
	@Override
	public void destroy() throws Exception {
		System.out.println("==It will be executed after being Destroyed==");
	}
}

注:目标Bean通过实现InitializingBean, DisposableBean接口,实现对应的afterPropertiesSet()和destroy()方法

第二种

/**第二种方式: 在注解@Bean是指定(initMethod = "init", destroyMethod = "destroy")**/
		System.out.println(applicationContext.getBean("createMyBean4"));
配置类:
@Bean(initMethod = "init", destroyMethod = "destroy")
	public MyBean4 createMyBean4() {
		return new MyBean4();
	}

目标Bean:
package com.harry.spring4.demo;

public class MyBean4 {
	/**
	 * 当Bean被Spring加载之后会执行
	 */
	public void init() {
		System.out.println("==It will be executed after being Loaded==");
	}
	
	/**
	 * 当Bean销毁之后会执行
	 */
	public void destroy(){
		System.out.println("==It will be executed after being Destroyed==");
	}
}


注:这里通过在配置类注解@Bean中标注initMethod , destroyMethod方法来实现,这也是实际开发中最常用的方式,基于Spring提供的@Bean注解的配置


第三种

/**第三种方式: 通过Javax(JSR-250)注解@PostConstruct和@PreDestroy方式**/
		System.out.println(applicationContext.getBean("createMyBean5"));
目标Bean:
package com.harry.spring4.demo;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class MyBean5 {
	/**
	 * 当Bean被Spring加载之后会执行
	 */
	@PostConstruct
	public void init() {
		System.out.println("==It will be executed after being Loaded==");
	}
	
	/**
	 * 当Bean销毁之后会执行
	 */
	@PreDestroy
	public void destroy(){
		System.out.println("==It will be executed after being Destroyed==");
	}
}



注:通过使用Javax注解@PostConstruct和@PreDestroy实现




//---------------------------------------这是一道华丽的分界线----------------------------------------------------

注入容器的三种方式


package com.harry.spring4.demo;

import javax.annotation.Resource;
import javax.inject.Inject;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Repository;
/**
 * Spring 依赖注入 
 * @author Harry Wan
 *
 */
public class MyDemo2 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.harry.**");
		
		//使用@Repository注解装配
		System.out.println(applicationContext.getBean("userDao"));
		//使用@Bean 自定义实例化对象装配
		System.out.println(applicationContext.getBean("createUserDao"));
		
				/**注入的三种方式**/
		//@Autowired 依赖 UserDao    ---Spring提供的注入方式,可以指定具体装配哪一个
		//@Resource 依赖User		   ----JSR-250提供的注入方式(JDK自带)
		//@Inject 依赖MyBean		   ----JSR-330提供的注入方式(需要添加依赖)
		UserService userService = applicationContext.getBean(UserService.class);
		
		//在有多个实例化Bean的情况下,默认情况下,Spring优先会注入@Repository注解的组建Bean,
		//可以在@Autowired下使用@Qualifier(value = "createUserDao")或者在@Bean下使用@Primary来指定装配哪一个
		System.out.println(userService);
		
		applicationContext.close();
	}
}


package com.harry.spring4.demo;

import javax.annotation.Resource;
import javax.inject.Inject;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService {
	@Autowired
	@Qualifier(value="createUserDao")
	private UserDao userDao;
	
	//JSR-250提供的注入方式(JDK自带)
	@Resource
	private User user;
	
	//JSR-330提供的注入方式(需要添加依赖)
	@Inject
	private MyBean myBean;

	@Override
	public String toString() {
		return "UserService [userDao=" + userDao + ", user=" + user + ", myBean=" + myBean + "]";
	}
	
	
	
}

@Bean
	//@Primary
	public UserDao createUserDao(){
		return new UserDao();
	}


注:第一种方式: 最常用的方法,使用Spring提供的@Autowired注解,当容器中有多个依赖注入的Bean对象时,可以使用
@Qualifier(value = "createUserDao")或者在@Bean下使用@Primary来指定装配哪一个
        第二种方式:使用JSR-250提供的注入方式(JDK自带),基于注解@Resource依赖注入
       第三种方式:使用JSR-330提供的注入方式(需要添加依赖), 基于注解@Inject实现依赖注入






//-------------------------------这是一道华丽的分界线----------------------------------------------------

基于注解设置在Spring扫描包时自动忽略相应Bean的装配:

package com.harry.spring4.demo;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.stereotype.Service;

public class MyDemo3 {
	public static void main(String[] args) {
		/**
		 * 把扫描包的注解配置信息添加在AnnotationScanConfig中,通过Spring容器读取配置文件的方式加载扫描配置
		 * @ComponentScan(basePackages="com.harry.**",excludeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={UserService.class,MyConfig.class}))
		 * 排除用@Service注解的UserService和在MyConfig中自定义配置的Bean的扫描
		 * 
		 * 如若使用@Component注解注释的Bean,可直接排除
		 * 如若使用Config配置文件自定义实例化Bean的方式,不能直接排除Bean的本身,要填写Config配置类,从而来排除配置文件中配置的Bean
		 * 
		 */
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationScanConfig.class);
		System.out.println(applicationContext.getBean(User.class));
		System.out.println(applicationContext.getBean(UserService.class));
		System.out.println(applicationContext.getBean(MyBean.class));
		applicationContext.close();
	}
}


扫描配置AnnotationScanConfig.java
package com.harry.spring4.demo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(basePackages="com.harry.**",excludeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={UserService.class,MyConfig.class}))
public class AnnotationScanConfig {

}


注: 使用@Configuration表示当前为以配置类加入到Spring容器中, @ComponentScan表示Spring扫描的配置信息,通过指定excludeFilters来过滤相应Bean的装配,FilterType.ASSIGNABLE_TYPE表示我们传入指定的要忽略的目标Bean的类型或者Bean所在的配置类。
     如果Bean使用的是@Component等注解标识,可以直接在Filter中指定该Bean的类型,从而忽略装配
     如果Bean使用的是配置类的方式,在配置类中使用@Bean的注解自定义实例化Bean,我们需要将配置类加到Filter中,从而对该Bean进行忽略,若加Bean本身,而非其Bean所在的配置类,则达不到忽略的效果



最后,由于Bean都是默认以单例的形式装配在Spring容器中,我们可以通过@Scope(scopeName = "prototype")来标识,表示每次从容器中获取该Bean是都是重新实例化一个新的对象。


Demo运行示例:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值