深圳营销网站建设策划,怎么在网站上做音乐,注册网站免费注册,上海私人做网站1.什么是IoC
Spring IoC#xff08;Inversion of Control#xff0c;控制反转#xff09;是Spring框架的核心之一#xff0c;它是一种设计模式#xff0c;也称为依赖注入#xff08;Dependency Injection#xff0c;DI#xff09;。在传统的程序设计中#xff0c;对象…1.什么是IoC
Spring IoCInversion of Control控制反转是Spring框架的核心之一它是一种设计模式也称为依赖注入Dependency InjectionDI。在传统的程序设计中对象之间的依赖关系通常由程序员在类内部直接创建和管理而在IoC容器中对象的创建和管理由容器来负责程序员只需要定义对象的依赖关系由容器来实现对象的创建和组装即把对象的控制权交给IoC容器所以叫控制反转。
接下来我们通过一个例子来类比解释什么是IoC
1.1 传统程序的开发
需求造一辆汽车。
实现思路先设计轮子然后根据轮子大小设计底盘接着根据底盘大小设计车身最后根据车身设计好整个汽车。在这个过程中出现了一个“依赖”关系汽车依赖车身车身依赖底盘底盘依赖轮子。
最后实现的代码如下
public class Main {public static void main(String[] args) {Car car new Car();car.run();}
}class Car {private Framework framework;public Car() {framework new Framework();System.out.println(car init);}public void run() {System.out.println(car run run!);}
}//车身
class Framework {private Bottom bottom;public Framework() {bottom new Bottom();System.out.println(Framework init);}
}//底盘
class Bottom {private Tire tire;public Bottom() {tire new Tire();System.out.println(bottom init);}
}//轮子
class Tire {//轮子尺寸private int size;public Tire() {this.size 15;System.out.println(tire init);}
}如果现在要求轮子的大小要为20我们就要给Tire类添加一个有参数的构造方法与此同时Bottom类Framework类Car类都需要修改如果我现在又要给轮子添加一个属性 颜色 此时所有依赖Tire类的类又都要修改由此可见这样的开发方式是存在弊端的。
1.2 IoC 程序开发
public class Main {public static void main(String[] args) {Tire tire new Tire();Bottom bottom new Bottom(tire);Framework framework new Framework(bottom);Car car new Car(framework);car.run();}
}class Car {public Car(Framework framework) {System.out.println(car init);}public void run() {System.out.println(car run run!);}
}//车身
class Framework {public Framework(Bottom bottom) {System.out.println(Framework init);}
}//底盘
class Bottom {public Bottom(Tire tire) {System.out.println(bottom init);}
}//轮子
class Tire {//轮子尺寸private int size;public Tire() {this.size 15;System.out.println(tire init);}
}
我们把创建对象交给Main类去做达到了其他类之间的解耦合效果无论其他类怎么变化整个的调用链是不需要调整的这里我们的Main类就可以称作IoC容器。
在Spring中IoC容器负责管理Java对象之间的依赖关系。当应用程序启动时IoC容器会读取配置文件或注解信息根据这些信息来实例化对象并将这些对象之间的依赖关系注入到对象中。这种方式使得应用程序的组件之间解耦易于维护和扩展。
1.3 DI
DI全称为依赖注入Dependency Injection是面向对象编程中的一种设计模式。它是控制反转Inversion of ControlIoC思想的一种具体实现方式。
简单来说依赖注入是指在创建对象时将其所依赖的其他对象的引用注入到对象中而不是由对象自己创建或查找依赖的对象。这样做的目的是降低模块之间的耦合度使得对象之间的依赖关系更加灵活、可维护和易于测试。
2. IoC/DI 使用
我们已经对IoC和DI有初步的了解接下来我们具体学习Spring IoC 和 DI的代码实现。
Spring 容器管理的主要是对象这些对象我们称之为“Bean” 我们把这些对象交由Spring管理由Spring来负责对象的创建和销毁我们程序只需要告诉Spring哪些需要存以及如何从Spring取出对象。
使用Component注解可以表示把某个类交给Spring来管理使用Autowired注解注入运行时依赖的对象
public class Main {public static void main(String[] args) {Car car new Car();car.run();}
}
Component
class Car {Autowiredprivate Framework framework;public Car() {System.out.println(car init);}public void run() {System.out.println(car run run!);}
}//车身
Component
class Framework {Autowiredprivate Bottom bottom;public Framework() {System.out.println(Framework init);}
}//底盘
Component
class Bottom {AutowiredTire tire;public Bottom() {System.out.println(bottom init);}
}//轮子
Component
class Tire {//轮子尺寸private int size;public Tire() {this.size 15;System.out.println(tire init);}
}
3. IoC详解
3.1 Bean的存储
在上面的案例中我们知道要把某个对象交给IoC容器管理需要在类上添加一个注解Component 而Spring框架为了更好的服务Web程序提供了更丰富的注解
类注解ControllerServiceRepositoryComponentConfiguration方法注解Bean
3.1.1 类注解
Controller Controller 注解用于标识一个类作为Spring MVC框架中的控制器负责处理用户请求并返回相应的视图。通常用于标识处理HTTP请求的控制器类可以与 RequestMapping 注解结合使用实现请求映射和页面跳转。Service Service 注解用于标识一个类作为业务层的组件通常用于标识服务层的类通过该注解告诉Spring该类是业务逻辑处理的组件可以被注入到其他类中使用。Repository Repository 注解用于标识一个类作为数据访问层的组件通常用于标识数据访问对象DAO类通过该注解告诉Spring该类是用于数据库访问的组件可以捕获数据库异常并将其重新抛出为Spring的数据访问异常。Component Component 注解是Spring中所有具体组件的通用形式用于标识一个类作为Spring容器管理的组件表示该类会自动被Spring加载并可以通过依赖注入来使用。Configuration Configuration 注解用于标识一个类作为配置类通常用于定义Bean的创建和依赖关系。该注解通常与 Bean 注解一起使用用于替代XML配置文件实现Java Config的方式进行配置。 这个和我们上期讲的应用分层是呼应的让程序员看到类注解后就能知道当前类的用途 使用演示
这些注解的使用方式都相同我们通过Controller来演示
Controller//将对象储存到Spring中
public class UserController {public void say() {System.out.println(Hello Controller);}
}
如上述代码我们只需在类上面加上Controltroller 注解即可把该类的对象储存在Spring中。
我们如何知道这个对象已经存在Spring容器中了呢接下来我们学习如何从Spring容器中获取对象
SpringBootApplication
public class J20240323SpringIocApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context SpringApplication.run(J20240323SpringIocApplication.class, args);//从Spring上下文中获取对象UserController userController context.getBean(UserController.class);//调用say方法userController.say();}
} 可以看到项目启动后成功打印了 Hello Controller
解释
ApplicationContext译为程序上下文用于表示 Spring 容器并且负责管理 Bean 的生命周期和配置信息。即可以理解为包含了Spring容器里的所有内容所有我们可以从ApplicationContext对象中获取Bean.
getBean()是BeanFactory接口中的一个方法ApplicationContext实现了BeanFactory接口我们打开BeanFactory的源码
我们发现重载了五个getBean方法 我们刚才是通过类对象获取的Bean所以我们使用的是第四个我们接下来再学习第一个和第二个的使用
1. getBean(String name)
根据Bean的名称获取BeanSpring会给管理的Bean按照小驼峰的方式命名
SpringBootApplication
public class J20240323SpringIocApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context SpringApplication.run(J20240323SpringIocApplication.class, args);//从Spring上下文中获取对象//通过类对象获取UserController userController1 context.getBean(UserController.class);userController1.say();//通过对象名获取UserController userController2 (UserController)context.getBean(userController);userController2.say();}
}
注意Spring官方文档中关于Bean的名称有这样一个注意事项 当类名的前两个字符都是大写字母时将按照类起初的名字来命名。
2. getBean(String name, ClassT requiredType)
通过名称和类对象获取Bean:
SpringBootApplication
public class J20240323SpringIocApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context SpringApplication.run(J20240323SpringIocApplication.class, args);//从Spring上下文中获取对象//通过类对象获取UserController userController1 context.getBean(UserController.class);userController1.say();//通过对象名获取UserController userController2 (UserController)context.getBean(userController);userController2.say();//通过类对象和对象名获取UserController userController3 context.getBean(userController, UserController.class);userController3.say();}
}
注意上述几种方式获取到的对象都是同一个对象把类交给Spring管理时默认是单例模式。
ApplicationContext对比BeanFactory
上面我们演示的是使用ApplicationContext来获取Bean我们也可以使用BeanFactory获取Bean接下来我们讲解一下它们的区别和联系
区别
初始化时机BeanFactory 是在第一次请求获取 Bean 时才进行实例化和初始化延迟加载而 ApplicationContext 在容器启动时就将所有 Bean 进行实例化和初始化。性能ApplicationContext 比 BeanFactory 更强大也更复杂因为 ApplicationContext 支持更多的特性如国际化处理、事件传播、AOP 管理等所以在性能上 BeanFactory 会更轻量级一些。功能ApplicationContext 继承自 BeanFactory并且提供了更多的高级特性如自动装配、消息资源处理、事件传播等。因此ApplicationContext 功能更加强大。
联系
ApplicationContext 可以看作是 BeanFactory 的扩展版本提供了更多功能和便利是更高级的容器接口。无论是 BeanFactory 还是 ApplicationContext它们都负责管理 Bean 实例的生命周期、依赖注入等工作是 Spring 框架中重要的组件。在实际开发中如果应用对性能要求较高可以使用 BeanFactory如果需要更多的企业级特性和功能建议使用 ApplicationContext。通常情况下我们更倾向于使用 ApplicationContext因为它提供了更多的便利和功能能够更好地支持复杂的应用场景。
3.1.2 方法注解
类注解是添加到类上面的但是存在两个问题
使用外部包里的类没办法添加类注解一个类需要多个对象
这种场景就需要使用方法注解Bean
使用方法
Bean注解需要在类注解注解下的类中使用使用时创建一个函数返回一个想要交给Spring管理的对象即可
Controller
public class UserController {public void say() {System.out.println(Hello Controller);}Beanpublic User getUser1() {return new User();}Beanpublic User getUser2() {return new User();}
}
注意使用Bean注解交给Spring管理的对象的名称和方法名一致获取Bean时如果对应类的对象在Spring中存在多个则不能只通过类对象获取
SpringBootApplication
public class J20240323SpringIocApplication {public static void main(String[] args) {User user1 (User) context.getBean(getUser1, User.class);user1.say();User user2 (User) context.getBean(getUser2, User.class);user2.say();System.out.println(user1 user2);}
} 3.2 扫描路径
一个对象要被Spring管理不仅需要加上注解还需要被Spring扫描到才行Spring的默认扫描路径是启动类所在的目录及子目录我们可以通过ComponentScan注解修改扫描路径
ComponentScan(basePackages com.example)
SpringBootApplication
public class J20240323SpringIocApplication {public static void main(String[] args) {SpringApplication.run(J20240323SpringIocApplication.class, args);}
}
4. DI 详解
4.1 属性注入
属性注入就是通过Autowired注解注入前面我们简单的演示过只需把Autowired写在对应的引用上即可获取对应对像的引用
Service
public class User {public void say() {System.out.println(helle);}
}Controller
public class UserController {Autowiredprivate User user;public void say() {user.say();}
} SpringBootApplication
public class J20240323SpringIocApplication {public static void main(String[] args) {ApplicationContext context SpringApplication.run(J20240323SpringIocApplication.class, args);UserController userController context.getBean(UserController.class);userController.say();}
} 4.2 构造方法注入
我只需在需要引入依赖的类中添加一个初始化的构造方法即可完成依赖注入
Controller
public class UserController {private User user;public UserController(User user) {this.user user;}public void say() {user.say();}
}
运行代码后同样能打印hello
注意交给Spring管理的类Spring会使用反射获取到对应类的构造方法来创建对象如果使用构造方法注入并且本类中存在多个构造函数需要使用Autowired指定使用哪个否者可能会出错
Controller
public class UserController {private User user;public UserController() {}Autowiredpublic UserController(User user) {this.user user;}public void say() {user.say();}
}
4.3 Setter 方法注入
给需要注入依赖的类添加带Autowired注解的set方法也可以注入依赖
Controller//将对象储存到Spring中
public class UserController {Autowiredpublic UserController(User user) {this.user user;}public void say() {user.say();}
}
4.4 三种注入方式的优缺点
4.4.1 属性注入 优点 简洁使用方便。 缺点 只能用于IoC容器非IoC容器不可用并且只有在使用的时候才会出现空指针异常NPE。不能注入一个Final修饰的属性。
4.4.2 构造函数注入 优点 可以注入final修饰的属性。注入的对象不会被修改。依赖对象在使用前一定会被完全初始化因为依赖是在类的构造方法中执行的而构造方法是在类加载阶段就会执行的方法。通用性好构造方法是JDK支持的所以更换任何框架它都是适用的。 缺点 注入多个对象时代码会比较繁琐。
4.4.3 Setter注入 优点 方便在类实例化之后重新对该对象进行配置或者注入。 缺点 不能注入一个Final修饰的属性。注入对象可能会被改变因为setter方法可能会被多次调用就有被修改的风险。
根据具体情况和需求可以选择适合的注入方式来管理对象之间的依赖关系。
4.5 Autowired存在的问题
当同一类型存在多个Bean时使用Autowired 会存在问题
public class User {String name;public User() {}public User(String name) {this.name name;}public void say() {System.out.println(name);}
}
Configuration
public class UserConfig {Beanpublic User User1() {return new User(a);}Beanpublic User User2() {return new User(b);}Beanpublic User User3() {return new User(c);}
}
Controller//将对象储存到Spring中
public class UserController {Autowiredpublic void say() {user.say();}
} 项目启动失败我们在描述这里看到Spring找到了三个对象 。使用Autowired注入时Spring会先根据对象的类型去寻找如果只找到一个就直接用如果找到多个再根据名称这里我们是user来寻找如果没有对应名称就会抛异常。
我们可以使用 Primary QualifierResource 这三个注解来解决。
Primary指定默认使用哪一个Bean
Configuration
public class UserConfig {PrimaryBeanpublic User User1() {return new User(a);}Beanpublic User User2() {return new User(b);}Beanpublic User User3() {return new User(c);}
} Qualifier指定使用Bean的名称
Controller//将对象储存到Spring中
public class UserController {Qualifier(User2)Autowiredprivate User user;public void say() {user.say();}
} 使用Resource注入依赖
Controller//将对象储存到Spring中
public class UserController {Resource(name User3)private User user;public void say() {user.say();}
} 5. 总结
Spring Spring 是一个开源的Java框架它提供了丰富的功能和组件用于简化企业级应用程序的开发。Spring 框架提供了依赖注入、面向切面编程、事务管理、数据访问等功能是一个全面的企业应用开发解决方案。Spring MVC Spring MVC 是 Spring 框架中的一个模块即Spring功能的一部分用于构建 Web 应用程序的 MVCModel-View-Controller架构。Spring MVC 提供了基于注解的方式来定义控制器、处理请求和渲染视图使得开发 Web 应用程序更加简单和灵活。Spring Boot Spring Boot 是基于 Spring 框架的快速开发框架它简化了 Spring 应用程序的搭建和部署过程。Spring Boot 提供了自动配置、约定优于配置、快速启动等特性使得开发者可以更快速地搭建和运行 Spring 应用程序而不需要进行繁琐的配置。简单来说Spring Boot 就是对Spring的使用做了一些简化使我们开发效率更高但其所有的功能都是基于Spring实现的。