Spring_Bean配置_生命周期_注解

本文详细介绍了Spring框架的核心概念,包括控制反转(IOC)、依赖注入(DI)以及Spring的生命周期。通过实例展示了如何通过XML配置和注解装配Bean,以及Bean的作用域和生命周期管理。此外,还探讨了Spring的优点,如简化开发、提供AOP支持和声明式事务管理等。

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

Spring

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

Spring核心

1.控制反转(IOC)
2.面向切面(AOP)

Spring优点

1.解耦, 简化开发: Spring就是一个工厂,可以将所有对象创建和依赖关系维护交给Spring处理
2.AOP支持: 方便实现事务处理, 权限处理, 监控操作
3.声明式事务支持: 只需通过配置就可以完成事务管理
4.提供Junit支持
5.集成其他框架
6.对JavaEE API的封装, 降低开发难度

Spring体系结构

Spring是一个分层架构, 包含的功能可分为大约20个模块.

Core Container(核心容器):
	Beans: 管理Beans
	Core: Spring核心
	Context: 配置文件
	ExpressionLanguage: SpEL表达式
AOP(切面编程)
AOP框架: Aspects
Data Access(数据库整合):
	JDBC, ORM, OXM, JMS, Transaction
Web(MVC Web开发):
	Web, Servlet, Portlet, Struts
Test(Junit整合)

IOC(控制反转)

IOC(控制反转): 将创建对象实例交给Spring处理, 每次从Spring工厂中获得对象
下面使用一个简单的例子说明:

目标类:

public interface UserService{
	void addUser();
}
public class UserServiceImpl implements UserService {
	public void addUser() {
		System.out.println("ico add user");
	}
}

Spring的配置文件:
配置文件名, 放置的位置都是任意的, 一般将配置文件命名为applicationContext.xml, 放置在src下

src目录下的applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--xsd约束-->
<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">
<!--
	id: Spring帮你new 的那个对象名
	class: 那个对象的全类名
-->
<bean id="userService" class="com.a_ioc.UserServiceImpl"></bean>
</beans>

测试代码:

public class TestIoc {
	
	@Test
	public void f1(){
		//XMLPATH代表配置文件所在的位置
		String XMLPATH="applicationContext.xml";
		
		//使用ClassPathXMLApplicationContext(String path)加载指定位置的配置文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(XMLPATH);
		
		//使用applicationContext的getBean获得配置文件中id为userService的对象
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.addUser();
	}
}

测试方法中不再使用new的方式获得对象, 而是通过控制反转, 将new的行为交给Spring处理(反射机制)

DI(依赖注入)

DI依赖注入: 对实例对象的属性赋值, 一般通过set方法进行反射赋值.
对象的属性一般指另一个对象(就有依赖一说)
下面使用例子说明DI

User的Service层:

public interface UserService{
	void addUser();
}

public class UserServiceImpl implements UserService {
	//对UserDao对象做依赖注入, 在后面生成get/set方法
	private UserDao userDao;
	
	public void addUser() {
		userDao.save();
	}

	public UserDao getUserDao() {
		return userDao;
	}
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
}

User的Dao层:

public interface UserDao {
	void save();
}

public class UserDaoImpl implements UserDao {
	public void save() {
		System.out.println("di save");
	}
}

applicationContext.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">

<!--
	property标签用于依赖注入:将ref映射的对象注入到name中
		name:需要注入的属性名
		ref:映射到UserDao对象
-->
	<bean id="userService" class="com.b_di.UserServiceImpl">
		<property name="userDao" ref="userDao"></property>
	</bean>
	<bean id="userDao" class="com.b_di.UserDaoImpl"></bean>
</beans>

测试:
测试中代码与前面一样几乎不变, 对象的生成, 对象属性的赋值都交给Spring处理, 高度解耦

public class TestDi {
	
	@Test
	public void f1(){
		String XMLPATH="applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(XMLPATH);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.addUser();
	}
}

Spring核心API

类结构图

顶级接口: BeanFactory
	用于生成任意的Bean, 采取延迟加载策略, 使用getBean才会初始化Bean
	
BeanFactory子接口: ApplicationContext
	功能加强, 使用该接口, 当配置文件被加载的时候, 就进行对象实例化
	
ApplicationContext子接口:
	1.ClassPathXmlApplicationContext用于加载src下的xml
		运行时, xml在/WEB-INF/classes/...xml
	2.FileSystemXmlApplicationContext加载指定盘符下的xml
		运行时, xml在/WEB-INF/...xml 

举例说明BeanFactory

public class TestBeanFactory {
	
	@Test
	public void f1(){
		String XMLPATH="applicationContext.xml";
		//加载完配置文件后, 并不会实例化
		BeanFactory applicationContext = new XmlBeanFactory(new ClassPathResource(XMLPATH));
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.addUser();
	}
}

调用ClassPathXmlApplicationContext(XMLPATH)加载配置文件, Spring就会调用配置文件中的配置的bean的构造函数, 而XMLBeanFactory(Resource)不会, 只是单纯加载配置文件, 只有当getBean才会调用构造函数

基于XML装配Bean

3种Bean实例化方式:
默认构造获得Bean, 使用静态工厂获得Bean, 使用实例工厂获得Bean

  • 使用默认构造函数:
使用如下标签配置Bean
<bean id="..." class="..."></bean>
注: 该Bean必须有默认构造函数(使用默认构造进行反射生成)
  • 静态工厂:
<bean id="" class="工厂全类名" factory-method="静态方法"></bean>

举例说明:
静态工厂:
	public class StaticBeanFactory {
		public static UserService newUserService(){
			return  new UserServiceImpl();
		}
	}
测试静态工厂:
public class TestStaticFactory {
	
	@Test
	public void f1(){
		String XMLPATH="applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(XMLPATH);
		UserService userService = (UserService) applicationContext.getBean("userService1", UserService.class);
		userService.addUser();
	}
}

application.xml:
	<bean id="userService1" class="com.c_createBean.StaticBeanFactory" factory-method="newUserService"></bean>
  • 实例工厂:
    先获得工厂的实例对象, 然后通过实例对象创建想要的对象, 实例工厂提供的方法都是非静态方法
实例工厂:
public class MyBeanFactory {
	public UserService newUserService(){
		System.out.println("MyBeanFactory newUserService");
		return  new UserServiceImpl();
	}
}

测试方法:
@Test
	public void f1(){
		String XMLPATH="applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(XMLPATH);
		UserService userService = (UserService) applicationContext.getBean("userService2", UserService.class);
		userService.addUser();
	}

applicationContext.xml:
<!--获得工厂实例-->
<bean id="myBeanFactory" class="com.c_createBean.MyBeanFactory"></bean>
<!--通过工厂实例调用方法获得指定对象-->
<bean id="userService2" factory-bean="myBeanFactory" factory-method="newUserService"></bean>

Spring中Bean种类

普通Bean: Spring直接创建实例
	<bean id="普通Bean名" class="普通Bean"></bean>
	
FactoryBean: 生产特定Bean的工厂,可以是静态/非静态工厂
非静态举例
	<bean id="工厂对象名" class="工厂类"></bean>
	<bean id="特定Bean" factory-bean="工厂对象名" factory-method="工厂方法名">
	
BeanFactory: 使用动态代理生成任意的Bean

Bean作用域

确定Spring创建Bean实例个数, 在bean标签中使用scope属性确定

singleton(默认值):
	在Spring中只存在一个Bean实例, 单例模式.
prototype:
	getBean()的时候都会new Bean(), 多例
request:
	每次http请求都会创建一个Bean, 仅用于WebApplicationContext环境
session:
	同一个http session共享一个Bean, 不同Session使用不同的Bean, 使用环境同上
globalSession:
	用于Portlet, 环境同上

<bean id="..." class="..." scope="..."></bean>

Spring生命周期

生命周期详情:

1.instantiate bean对象实例化
2.populate properties 封装属性
3.如果Bean实现BeanNameAware 执行 setBeanName
4.如果Bean实现BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext
5.如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
6.如果Bean实现InitializingBean 执行 afterPropertiesSet 
7.调用<bean init-method="init"> 指定初始化方法 init
8.如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
9.执行业务处理
10.如果Bean实现 DisposableBean 执行 destroy
11.调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy
  • 初始化与销毁
    在构造方法前->初始化, 容器关闭时->销毁
bean标签写法:
<bean id="..." class="..." init-method="初始化方法名" destory-method="销毁方法名">
实现初始化与销毁必须满足:
	容器必须close, 此时销毁方法执行
	必须是单例

下面使用一个简单例子演示:

applicationContext.xml:
	<bean id="userService" class="com.e_lifeCycle.UserServiceImpl" init-method="myInit" destroy-method="myDestory"></bean>

UserServiceImp.java:
public class UserServiceImpl implements UserService {
	public void addUser() {
		System.out.println("lifeCycle add User");
	}
	public void myInit() {
		System.out.println("init");
	}
	public void myDestory() {
		System.out.println("destory");
		
	}
}

Test:
	@Test
	public void f1(){
		String XMLPATH="com/e_lifeCycle/applicationContext.xml";
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(XMLPATH);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.addUser();
		//ApplicationContext没有close方法, 使用ClassPathXmlApplication
		applicationContext.close();
	}
//在执行构造完Bean对象的时候执行myInit
//在容器关闭之前执行myDestory
  • BeanPostProcessor实现AOP, 完成事务处理
    Bean实现BeanPostProcessor, 当Spring管理Bean的时候,
    就能在初始化方法前执行PostProcessAfterInitialization(Object bean, String beanName);
    在初始化方法后执行PostProcessBeforeInitialization(Object bean, String beanName);

下面举例说明:

编写BeanPostProcessor:
public class PostProcessor implements BeanPostProcessor{
	/**
	 * 执行方法之前调用, 就意味着在初始化的时候就会调用事务处理
	 * 此时的事务处理是针对接口中有的方法
	 */
	@Override
	public Object postProcessBeforeInitialization(final Object bean, String beanName)
			throws BeansException {
		System.out.println("方法前"+beanName);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(final Object bean, String beanName)
			throws BeansException {
		System.out.println("方法后"+beanName);
		return Proxy.newProxyInstance(
				PostProcessor.class.getClassLoader(), 
				bean.getClass().getInterfaces(), 
				new InvocationHandler() {
					//反射重写invoke, 实现AOP
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						System.out.println("开启事务");
						Object objectInvoke = method.invoke(bean, args);
						System.out.println("关闭事务");
						return objectInvoke;
					}
				});
	}
}

在applicationContext.xml中配置:
<bean class="com.e_lifeCycle.PostProcessor"></bean>
注册自定义的BeanPostProcessor

测试类:
测试类就是前面的初始化与销毁代码
运行结果:
	构造
	方法前userService
	init
	方法后userService
	开启事务
	lifeCycle add User
	关闭事务
	destory

生命周期, 事件执行流程

使用上面的lifeCycle作为例子

1.加载配置文件, 构造方法执行
2 装载属性,调用setter方法
3.通过BeanNameAware接口,获得配置文件id属性的内容:lifeUser
4.通过ApplicationContextAware接口,获得Spring容器
5. 实现BeanPostProcessor后处理,初始化前,执行postProcessBeforeInitialization方法
6.通过InitializingBean,确定属性设置完成之后执行
7.配置init-method执行自定义初始化方法
8. 实现BeanPostProcessor后处理,在自定义初始化之后,执行postProcessAfterInitialization方法
9.通过DisposableBean接口,不需要配置的销毁方法
10.配置destroy-method执行自定义销毁方法

属性依赖注入

1.通过构造方法进行装配:
在bean标签中添加constructor-arg标签进行装配.
例如:

<bean id="..." class="...">
	<constructor-arg name="username" value="jack"></constructor-arg>
	<constructor-arg index="0" type="java.lang.String" value="jack"></constructor-arg>
	<constructor-arg name="username" ref="userService"></constructor-arg>
</bean>

name: 构造函数的参数名称
value: 为属性注入普通类型数据
index: 构造函数第几个参数
type: 构造函数参数的类型, 结合index使用
ref: 为属性注入其他Bean

注: 使用这个参数每次都是调用Bean中首次与标签中数据匹配合适构造函数

2.使用setter方法注入:
就是使用property标签指定name, value/ref值

<bean id="..." class="...">
	<property name="username" value="jack"></property>
</bean>

P命名空间
主要对"setter方法依赖注入"做简化, 替换property.
在添加P命名空间:
在beans标签中添加: xmlns:p=“http://www.springframework.org/shema/p

将原来的:
	<bean id="..." class="...">
		<property name="username" value="jack"></property>
	</bean>
变为:
	<bean id="..." class="..." p:name="username" p:value="jack"></bean>

SPEL
用于简化property中属性名, 与属性值的写法, 类似于EL表达式

<property name="属性名" value="#{表达式}"></property>
#{123}, #{'jack'} => 代表数字, 字符串
#{beanId} => 另一Bean的引用
#{beanId.propertyName} => 使用另一个beanId的属性值为当前bean的属性值赋值
#{beanId.clone()} => 使用beanId的方法为bean属性赋值
#{T().字段|方法} => 使用其他类的字段或方法为bean赋值

例:

<property name="cname" value="#{'jack'}"></property>
<property name="cname" value="#{customerId.cname.toUpperCase()}"></property>

通过另一个bean,获得属性,调用的方法
<property name="cname" value="#{customerId.cname?.toUpperCase()}"></property>
?. 代表: 如果对象不为null,将调用方法

4.集合注入:
在property标签中注入集合数据

注入数组:
<property name="属性名">
	<array>
		<value>A</value>
		<value>B</value>
		<value>C</value>
	</array>
</property>

注入List/Set只需将<array>改为<list>, <set>

注入Map:
<property name="属性名">
	<map>
		<entry key="1" value="A"></entry>
		<entry>
			<key><value>2</value></key>
			<value>B</value>
		</entry>
		上面这两种写法效果一样
	</map>
</property>

注入Properties数据:
<property name="propsData">
	<props>
		<prop key="1">A</prop>
		<prop key="2">B</prop>
	</props>
</property>

基于注解装配Bean

使用注解的前提:

在 beans 标签下添加 context:component-scan标签, 扫描包下所有类的注解
<context:component-scan base-package="com.itheima.g_annotation.a_ioc"></context:component-scan>

取代 bean 标签的注解:

1. @Component("beanId")
	等价于<bean id="beanId" class="...">
	
	@Component("userServiceId")
	public Class UserServiceImpl implements UserService{
		//..............	
	}
	
2. 在web中, 提供3个注解用于标识三层架构, 这3个注解效果与Component一样
	@Repository: dao层
	@Service: service层
	@Controller: web层

取代setter依赖注入的注解:
在类中对象的属性上加注解, 就能完成注入(没有setter方法也可以注入)

1.普通数据类型值: @Value("属性值")
	@Value
	private UserService userService;
	
2.引用数据类型值: 
	按照类型注入: @Autowired
		@Autowired
		private UserService userService;
	按照名称注入: @Autowired@Qualifier("...") 或者 @Resource("...") 两注解效果一样
		//使用service层生成的userService对象进行注入
		@Autowired@Qualifier("userService")
		private UserService userService;
		
3.生命周期: 配置init-method, destroy-method属性
	初始化:@PostConstruct
		@PostConstruct
		public void myInit(){......}
	销毁: @PreDestroy
		@PreDestroy
		public void myDestroy(){......}
		
4.作用域: 配置scope属性
	@Scope("prototype")
	配置多例

上面有错, 还请指出, 如果认为我写的还不错, 还请点个赞, 多多支持一下, O(∩_∩)O~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值