springboot2.x对应spring5、springboot3.x对应spring6
即 Ioc容器在运行期间,动态的将某种依赖关系自动注入
bean属性
id属性 | 设置容器键的名称 id或name 不写的话就是class名+“#0” |
class | 设置类的全路径,底层通过反射创建对象 |
init-method | 初始化方法 |
destroy-method | 销毁方法 |
lazy-init | 懒加载(默认是立即加载) |
scope | 作用域,表示单例(默认singleton)还是多例(prototype),request(Web应用中一次请求中有效),session,表示不同的session使用不同的对象 |
primary | 如果一个接口在容器中存在多个实现类,设置为true表示优先选择该实例 |
注意:如果不是懒加载的话就表示对象在容器创建的时候就立即加载 ,懒加载是用的时候才加载
@Component代表=service controller,repository那些,是大的注解
@Configuration
public class DbUtilsConfig {
// 默认情况Bean的Id是方法名称
// Method 执行方法 返回值 获取方法名称 获取方法的参数
@Bean
public DbUtils dbUtils(DataSourceUtils dataSourceUtils) {
DbUtils dbUtils = new DbUtils();
dbUtils.setDataSourceUtils(dataSourceUtils);
return dbUtils;
}
@Bean
public DataSourceUtils dataSourceUtils() {
DataSourceUtils dataSourceUtils = new DataSourceUtils();
return dataSourceUtils;
}
}
注意:全局对注解的扫描也是要开启的 ,必须使用public,返回值必须是注册的对象或者接口,在里面new的时候可以去new他的实现类
注意:想要调用destory方法,就必须有一个关闭容器的方法
自动生成类的getter
、setter
、equals()
、hashCode()
和toString()
方法
自动生成一个无参构造函数
自动生成一个包含类中所有字段的构造函数
通过构造方法给对象的属性赋值
(1)name 通过参数的名称
(2) index 通过参数数组的索引
(3)type 通过类型来赋值
(4)value设置基本数据类型的值
(5)ref设置引用类型的值 (指向容器中的某个对象)
属性
(1)name 属性的名称
(2)value设置基本数据类型的值
在容器中建立bean与bean之间的依赖关系的过程,class里面写实现类全路径,可以用接口
注意:两者必须在同一体系,不能一种是xml方式,另一种是直接new出来的
简写
注意:
v
@Autowired | @Resource | @Qualifier | @Inject(基本不用) |
spring提供的通过类型查找,如果存在则直接赋值 如果没有找到或者找到多个类型直接抛出异常 | 是jsr-250提供 1. 默认情况通过名字查找容器的对象 ,如果通过名字没找到对象,就会通过类型查找 如果都没有直接抛出异常 2. 如果给name属性赋值,只会通过name去查找对象,如果找不到直接抛出异常 3. 如果name属性根type属性都赋值, 两者都必须同时匹配.否则直接抛出异常 |
一定要配合@Autowire注解一起使用,通过名字来查找容器中的对象 | jsr-330提供 |
@Controller
public class UserController {
@Autowired
@Qualifier("userServiceImpl")
private UserService userService;
@Configuration
public class DbUtilsConfig {
// 默认情况Bean的Id是方法名称
// Method 执行方法 返回值 获取方法名称 获取方法的参数
@Bean
public DbUtils dbUtils(DataSourceUtils dataSourceUtils) {
DbUtils dbUtils = new DbUtils();
dbUtils.setDataSourceUtils(dataSourceUtils);
return dbUtils;
}
@Bean
public DataSourceUtils dataSourceUtils() {
DataSourceUtils dataSourceUtils = new DataSourceUtils();
return dataSourceUtils;
}
}
注意:必须使用public,返回值必须是注册的对象或者接口,在里面new的时候可以选择去new他的实现类,
@Configuration
public class DbUtilsConfig {
// 默认情况Bean的Id是方法名称
// Method 执行方法 返回值 获取方法名称 获取方法的参数
@Bean
public DbUtils dbUtils(DataSourceUtils dataSourceUtils) {
DbUtils dbUtils = new DbUtils();
dbUtils.setDataSourceUtils(dataSourceUtils);
return dbUtils;
}
@Bean
public DataSourceUtils dataSourceUtils() {
DataSourceUtils dataSourceUtils = new DataSourceUtils();
return dataSourceUtils;
}
}
通过在类的构造方法中接收外部提供的依赖来完成注入的方式。在Spring框架中,可以通过在构造方法上添加@Autowired
注解来实现自动注入
通过调用类的setter方法来注入依赖的方式。在Spring框架中,可以通过在setter方法上添加@Autowired
注解来实现自动注入。
问题描述:循环依赖指的是两个或多个Bean之间互相持有对方,形成了一个闭环。这种情况会导致一个Bean依赖于另一个Bean,而后者又依赖于前者,形成一个无限循环
2)构造器注入中,如果两个bean相互依赖,Spring无法同时创建它们,因为每个bean的创建都需要另一个bean作为参数。这种情况下,Spring无法解决循环依赖,会抛出一个BeanCurrentlyInCreationException异常。
3)Setter注入,对于Setter注入,Spring会首先创建bean的实例,然后通过setter方法注入依赖关系。所以Setter注入不会产生循环依赖问题。
循环依赖 三级缓存 提前暴露
循环依赖是什么:A 依赖 B,B 依赖 A
1、A 创建过程中需要 B,于是先将 A 放到三级缓存,去实例化 B。
2、B 实例化的过程中发现需要 A,于是 B 先查一级缓存寻找 A,如果没有,再查二级缓存,如果还没有,再查三级缓存,找到了 A,然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A。
3、B 顺利初始化完毕,将自己放到一级缓存里面(此时 B 里面的 A 依然是创建中的状态)。然后回来接着创建 A,此时 B 已经创建结束,可以直接从一级缓存里面拿到 B,去完成 A 的创建,并将 A 放到一级缓存。
当一个Bean被标记为@Lazy,Spring会延迟初始化这个Bean,直到它的一个属性被访问或者被注入到其他Bean中。
在循环依赖的情况下,使用@Lazy注解可以解决依赖初始化顺序的问题,因为依赖的Bean会在实际使用时才被加载。
当有多个同类型的Bean可供选择时,可以使用@Primary注解来指定首选的Bean。
在循环依赖的情况下,可以使用@Primary注解来指定先初始化的Bean,从而解决依赖问题。
有时候,循环依赖是由于代码结构或设计不当导致的。通过重构代码或调整Bean的依赖关系,可以消除循环依赖。
例如,将循环依赖的部分提取到一个单独的Bean中,或者调整Bean的初始化顺序。
在某些情况下,可以使用ApplicationContext的刷新机制来手动控制Bean的初始化。
通过在应用上下文刷新之前创建并配置所有的Bean,可以避免循环依赖的问题。
在某些情况下,循环依赖问题可能是由于Spring版本中的Bug导致的。升级到最新的Spring版本可能会解决这个问题。
有些第三方库或框架提供了解决循环依赖问题的机制或工具,可以尝试使用这些库或框架来解决循环依赖问题。
无反射,无框架、底层原理就是基于反射
org.springframework spring-context 5.3.31
//获取ioc容器 ApplicationContext apx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean UserService userService = (UserService) apx.getBean("userService");
userService.save();
ClassPathXmlApplicationContext关系图
使用对象时,由主动的new对象转为外部提供对象,此过程中对这创建控制权由程序转移到外部
@Service("ddd")
public class UserServiceImpl implements UserService {
}
name="dataSource,druidDataSource2"
性能和资源优化、共享状态、简化配置、避免多个线程同时访问同一个对象的情况,从而避免了状态不一致的问题
public class Test02 {
public static void main(String[] args) {
//获取ioc容器
ApplicationContext apx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
UserDao userDao = (UserDao) apx.getBean("userDao");
userDao.save();
注意:spring创建Bean的时候,调用的是无参的构造方法
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
orderDao.save();
package com.qf.factory;
import com.qf.dao.UserDao;
import com.qf.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;
public class UserDaoFactoryBean implements FactoryBean {
//代替原始实例工厂创建对象的方法
@Override
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//得到Bean类型
@Override
public Class> getObjectType() {
return UserDao.class;
}
//决定他是否是单例(默认单例)
@Override
public boolean isSingleton() {
return false;
}
}
package com.qf.controller;
import com.qf.service.UserService;
import com.qf.service.impl.UserServiceImpl;
import java.util.HashMap;
import java.util.Map;
public class UserController {
private UserService userService = new UserServiceImpl();
private Map ioc = new HashMap();
public String login(){
userService.toString();
//通过反射获取userserviceimpl的class对象
Class> cls = Class.forName("com.qf.service.impl.UserServiceImpl");
//实例化userService对象
Object o = cls.newInstance();
//获取类名(返回的是全类名)
String name = cls.getName();
//注入对象
ioc.put("userServiceImpl",o);
return "登录0";
}
}
通过spring配置文件 获取扫描的根路径
遍历根路劲下的所有.class结尾的文件
通过文件全路径获取class对象
通过class对象获取类的上的注入注解对象
如果对象不为空通过反射创建对象注册到容器中
注意:class.getAnnotation获取该class对象的注解
package com.qf;
import com.qf.controller.UserController;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
public class App {
public static void main(String[] args) {
Map ioc = new HashMap();
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
//通过类名获取class对象
Class cla = UserController.class;
//获取类上的注解
Component annotation = cla.getAnnotation(Component.class);
if (annotation !=null){
//实例化对象
UserController o = cla.newInstance();
//put进去
ioc.put("UserController",o);
}
}
}
这里
根据type的时候,bookdao的id都可以省略,因为它是根据类型来的,name就不行
name是对应这个名
100
200
300
你好
不错
学习
10
20
30
china
henan
kaifeng
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// ctx.registerShutdownHook();
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
写上
就可以在以接口接收的时候去调用实现类的方法
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
ctx.registerShutdownHook(); | 注册关闭钩子 |
ctx.close(); | 直接不保存关闭 |
会先调用dao的init方法
然后是service里面的set方法
service里的init方法
service的save
dao的save
service destroy
dao destory...
package com.qf.dao.impl;
import com.qf.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
// public UserDaoImpl() {
// System.out.println("book dao constructor is running...");
// }
//表示bean初始化对应的操作
public void init(){
System.out.println("Userdao init...");
}
public void save(){
System.out.println("user dao save...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("userdao destory...");
}
}
package com.qf.service.impl;
import com.qf.dao.OrderDao;
import com.qf.dao.UserDao;
import com.qf.service.UserService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
//@Service
public class UserServiceImpl implements UserService, InitializingBean, DisposableBean {
private UserDao userDao;
private OrderDao orderDao;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
public void save(){
System.out.println("user service save...");
userDao.save();
}
public void setUserDao(UserDao userDao) {
System.out.println("set userdao.......");
this.userDao = userDao;
}
@Override
public void destroy() throws Exception {
System.out.println("service destroy");
}
}
当你调用ctx.getBean(BookDao.class)
时,Spring会尝试找到一个实现了BookDao
接口的bean。然后当你调用ctx.getBean(BookDaoImpl.class)
时,Spring会找到一个名为BookDaoImpl
的bean(可能是通过名称匹配)。
//这
package com.qf.dao.impl;
import com.qf.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Repository
@Scope("singleton")
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("book dao save...");
}
@PostConstruct
public void init(){
System.out.println("init...");
}
@PreDestroy
public void destory(){
System.out.println("destory...");
}
}
package com.qf.service.impl;
import com.qf.dao.BookDao;
import com.qf.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDao2")
private BookDao bookDao;
@Override
public void save() {
System.out.println("book service save...");
bookDao.save();
}
}
@Autowired
注解用于自动装配bean,而
标签用于指定Spring扫描的包路径,以便自动发现并注册bean
即使你使用了@Autowired
注解,你仍然需要使用
标签来指定Spring扫描的包路径。因为
的作用是告诉Spring去哪些包下寻找需要被Spring管理的bean,并且注册这些bean到Spring容器中
所以,@Autowired
和
是相互补充的,前者用于自动装配,后者用于指定需要被扫描的包路径。两者一起使用,才能实现Spring的自动装配功能
当Spring容器启动时,它会扫描指定的包路径下的类,并注册带有@Component
、@Service
、@Repository
、@Controller
等注解的类为bean。然后,在需要使用这些bean的地方,你可以使用@Autowired
注解来自动装配它们
注意:@PropertySource("jdbc.properties")这样也行
52、注解写了别名的话就是指定的,没有的话就是类名首字母小写,
BookDao bookDao1 = ctx.getBean(BookDao.class);
BookDaoImpl book11 = ctx.getBean(BookDaoImpl.class);
是同一个东西(除非设置scope)
@Configuration
注解用于声明一个类作为配置类,该类包含一个或多个@Bean
方法,这些方法用于创建并返回一个或多个Spring容器管理的bean。这些bean将自动注册到Spring应用程序上下文中,并可通过其他bean进行注入。
@ComponentScan
注解用于告诉Spring自动扫描指定包(或多个包)下的类,并将它们作为组件自动注册到Spring应用程序上下文中。这使得您无需手动声明每个bean,而是可以让Spring自动发现和注册符合条件的组件。
通常情况下,您可以将@Configuration
和@ComponentScan
一起使用,以便在配置类中声明组件并提供自动扫描功能
(1)@Autowired 是spring提供的通过类型查找,如果存在则直接赋值 如果没有找到或者找到多个类型直接抛出异常
(2)@Resource 是jsr-250提供
(3)区别
1. 默认情况@Resource通过名字查找容器的对象 ,如果通过名字没找到对象,就会通过类型查找 如果都没有直接抛出异常
2. 如果给name属性赋值,只会通过name去查找对象,如果找不到直接抛出异常
3. 如果name属性根type属性都赋值, 两者都必须同时匹配.否则直接抛出异常