Spring
基本概念
Spring 是一个开源的、轻量级的 Java 企业级应用开发框架
- 控制反转(IoC):是一种设计思想,将对象的创建和依赖关系的管理从程序代码转移到外部容器,由容器来负责创建对象、管理对象的生命周期以及对象之间的依赖关系。
- 依赖注入(DI):是控制反转的一种实现方式,通过在对象创建时或运行时将依赖对象注入到目标对象中,使得目标对象不需要主动去创建或查找依赖对象,从而实现对象之间的解耦。
- 面向切面编程(AOP):是一种编程范式,它允许将与业务逻辑无关的横切关注点(如日志记录、事务管理、安全检查等)从业务逻辑中分离出来,以独立的切面形式进行模块化管理,提高代码的复用性和可维护性。
- Spring 容器:是 Spring 框架的核心,用于管理和配置应用程序中的对象。它负责对象的创建、初始化、装配和销毁等生命周期管理,主要有 BeanFactory 和 ApplicationContext 两种类型。
- Bean:在 Spring 中,由 Spring 容器管理的对象称为 Bean。可以通过配置文件或注解等方式将普通的 Java 对象定义为 Bean,使其能够享受 Spring 容器提供的各种服务。
作用
- 解耦和降低耦合度:通过 IoC 和 DI 机制,使得组件之间的依赖关系更加松散,降低了代码之间的耦合度,提高了代码的可维护性和可扩展性。
- 提高代码复用性:AOP 的应用使得横切关注点能够以切面的形式进行复用,避免了在多个业务逻辑中重复编写相同的代码。
- 简化开发流程:提供了一系列的功能和工具,如数据访问、事务管理、Web 开发等,简化了企业级应用开发的流程,提高了开发效率。
- 方便的配置管理:可以通过配置文件或注解等方式对 Bean 进行灵活的配置,方便地修改和调整应用程序的行为和参数。
应用场景
- 企业级应用开发:适用于构建各种规模的企业级应用,如电子商务系统、企业资源规划(ERP)系统、客户关系管理(CRM)系统等,满足企业级应用对高可维护性、高可扩展性和高性能的要求。
- Web 应用开发:在 Web 应用开发领域,Spring 提供的 Spring MVC 等框架为构建 Web 应用提供了便捷的方式,能够快速开发出功能强大、用户体验良好的 Web 应用程序。
- 微服务架构:在微服务架构中,Spring Boot 等相关技术为微服务的快速开发和部署提供了有力支持,方便地构建独立、可扩展和易于维护的微服务。
- 大数据和云计算:Spring 也在大数据和云计算领域有着广泛的应用,如与 Hadoop、Spark 等大数据框架的集成,以及在云计算平台上的部署和运行等。
优势
- 提高开发效率:通过提供丰富的功能和便捷的开发方式,减少了开发者编写大量重复代码的工作量,从而加快了项目的开发进度。
- 增强代码质量:其设计模式和架构理念有助于编写结构清晰、易于维护和扩展的代码,降低了代码的耦合度,提高了代码的可读性和可测试性。
- 跨平台和兼容性:Spring 具有良好的跨平台性,能够在不同的操作系统和应用服务器上运行,并且与各种开源和商业的技术框架和工具具有良好的兼容性。
- 社区支持和开源生态:拥有庞大而活跃的社区,开发者可以在社区中获取丰富的技术资源、文档、教程和开源库,同时也可以积极参与社区贡献,分享自己的经验和代码。
IoC容器
首先了解项目的结构
//我们项目拥有两个包,分别是service和dao,其下分别拥有一个接口和一个实现类,Service依赖Dao
public interface BookService{
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save(){
System.out.println("BookService Run !");
bookDao.save();
}
}
public interface BookDao{
public void save();
}
public class BookDaoImpl implements BookDao {
public void save(){
System.out.println("BookDao Run !");
}
}
此处使用传统的配置文件方法来将依赖放到IoC容器中。
第一步:导入Spring坐标
既然要使用Spring,首先应该导入其坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
第二步:创建配置文件
我们需要创建Spring配置文件,配置对应的类作为Spring管理的Bean
在resources
配置文件夹下声明Spring的配置类 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
</beans>
第三步:配置bean
在上面配置类模板中,添加如下配置,用来配置哪些类是被Spring管理的bean
<!--bean标签配置Bean
id属性给bean起名
class属性给bean定义类型
-->
<!--注意一定要配置实现类-->
<bean id="bookDao" class="com.angelday.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl"/>
配置项:
- id 属性
- 用于用于为该
bean
定义一个唯一的标识符。在整个 Spring 容器的配置范围内,id
的值必须是唯一的,不能与其他bean
的id
重复。 - 它主要用于在其他地方引用该
bean
,例如通过@Autowired
注解注入依赖时,就是根据bean
的id
或其默认名称(如果没有显式指定id
)来查找对应的bean
实例并注入到目标对象中的。 - 可以将其理解为一个对象在 Spring 容器中的 “名字”,通过这个 “名字”,Spring 能够准确地找到并管理对应的对象实例。
- 用于用于为该
- class属性
- 用于指定要实例化的类的全限定名,包括包名和类名。
- Spring 会根据这个全限定名,使用反射机制来创建该类的实例,并将其作为一个
bean
对象管理在容器中。 - 它告诉 Spring 具体要创建哪种类型的对象,以便 Spring 能够正确地进行实例化、初始化以及依赖注入等操作。
第四步:获取IoC容器
在程序的启动类中获取IoC容器
public class App {
public static void main(String[] args){
//获取IoC容器
//注意需要将配置文件作为参数放入该构造方法中
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
第五步:获取Bean
public class App {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Bean
//注意该方法需要将bean的名称作为参数传入
//并且该方法返回值为Object
Object bean = ctx.getBean("bookDao");
//所以需要强转换为BookDao类型
BookDao bookDao = (BookDao)bean;
//获取bean之后就可以使用了
bookDao.save();
}
}
通过以上步骤,我们成功地使用传统的配置文件方法将项目中的依赖放入了 Spring 的 IoC 容器中。这种方式为我们的项目带来了更好的结构和可维护性,使得对象之间的依赖关系更加清晰明了。然而,这仅仅是 Spring 强大功能的一部分。在接下来的章节中,我们将深入探讨 Spring 的依赖注入(DI)机制,了解它如何进一步优化我们的代码结构,提高开发效率,并实现更加灵活的应用程序设计。
DI
依赖注入,作为一种强大的设计理念和技术手段,在 Java 应用开发中发挥着至关重要的作用。它能够有效地降低代码之间的耦合度,使得各个模块之间的依赖关系更加清晰、易于管理。通过 DI,我们不再需要在对象内部手动创建其依赖的对象,而是由外部容器负责将所需的依赖对象注入到目标对象中。
删除 new
的方式
竟然知道不需要自己通过new
来创建对象,所以我们需要先吧业务代码中new
的部分删除
提供一个setter方法
public class BookServiceImpl implements BookService {
//private BookDao bookDao = new BookDaoImpl();
private BookDao bookDao;
public void save(){
System.out.println("BookService Run !");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
修改配置文件
我们需要告诉Spring,需要把Dao放到Service当中,所以我们需要修改bean的定义
<bean id="bookDao" class="com.angelday.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<!-- 配置Service与Dao的关系 -->
<!-- property标签长不魔置当前bean的属性
name属性表示配置哪一个具体的属件
ref属性表示参照哪一个bean
-->
<property name="bookDao" ref="bookDao"/>
</bean>
注意:
- property 标签:在 Spring 配置文件中,
<property>
标签用于设置 Bean 的属性值。在这里,它用于设置BookServiceImpl
的bookDao
属性。 - name属性:
<property>
标签的name属性指定了要设置的属性名称,这里是bookDao
,它必须与BookServiceImpl类中定义的BookDao类型的属性名称完全一致。 - ref属性:
<property>
标签的ref属性用于指定要注入的另一个Bean
的引用,这里的值是bookDao,它对应着前面配置的BookDao的< bean>标签的id属性,通过这种方式,Spring 容器会将id为bookDao的Bean实例注入到BookServiceImpl的bookDao属性中。
此时再运行main方法,发现代码任然正常运行,说明dao成功注入到service中
依赖注入
四种注入方式
前面说到将Dao注入到Service中,我们没有采用new
的方式,而是使用了Setter方法。
其实向一个类中传递数据,拥有两种方式
- 普通方法(set)
- 构造方法
依赖注入描述了容器中建立的bean与bean之间的依赖关系,传输数据我们可以分为两类
- 引用类型
- 简单类型(基本数据类型与String)
根据上面我们可以分为四种依赖注入方式
- setter注入
- 简单类型
- 引用类型
- 构造器注入
- 简单类型
- 引用类型
setter注入-引用类型
前面使用的方式就是这种方法,首先再bean中定义set方法,在配置中添加property标签,注入引用数据类型。
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save(){
System.out.println("BookService Run !");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
<bean id="bookDao" class="com.angelday.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
setter注入-简单类型
public class BookServiceImpl {
private int connectionNum;
private String databaseName;
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
此处配置文件略有不同
<bean id="bookDao" class="com.angelday.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<property name="connectionNum" value="10"/>
<property name="databaseName" value="mysql"/>
</bean>
注:前面我们知道
ref
属性表示参照哪一个bean,
由于此处是具体的值,所以使用value
属性
构造器注入-引用类型
使用构造器注入我们就不需要Set方法了,写一个构造方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
//构造方法
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save(){
System.out.println("BookService Run !");
bookDao.save();
}
}
并且配置文件中也不同
<bean id="bookDao" class="com.angelday.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<!-- 此处的name为构造方法的参数名 -->
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
配置细节
constructor-arg
标签:在 Spring 配置文件中,<constructor-arg>
标签专门用于向Bean
的构造函数传递参数。在这里,它用于向BookServiceImpl的构造函数传递BookDao实例。name
属性:<constructor-arg>
标签的name属性指定了构造函数中参数的名称,这里是bookDao
,它必须与BookServiceImpl
构造函数中定义的BookDao
类型参数
的名称完全匹配。ref
属性:与<property>
标签中的ref
属性作用类似,这里的ref属性指定了要注入的另一个Bean
的引用,其值为bookDao
,对应着前面配置的BookDao的<bean>
标签的id
属性。通过这种方式,Spring
容器会将id
为bookDao
的Bean
实例作为参数传递给BookServiceImpl的构造函数。
构造器注入-简单类型
public class BookServiceImpl {
private int connectionNum;
private String databaseName;
public BookServiceImpl(int connectionNum, String databaseName) {
this.connectionNum = connectionNum;
this.databaseName = databaseName;
}
}
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<!-- 此处的name为构造方法的参数名 -->
<property name="connectionNum" value="10"/>
<property name="databaseName" value="mysql"/>
</bean>
了解内容
<?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-4.0.xsd">
<!-- 此处的name名,必须为构造方法的形参名,提高了耦合,所以我们又另一种写法 -->
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<!-- 此处的name为构造方法的参数名 -->
<property name="connectionNum" value="10"/>
<property name="databaseName" value="mysql"/>
</bean>
<!-- 此方法解决了名称的耦合度 -->
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<!-- 此处的type为构造方法的数据类型 -->
<property type="int" value="10"/>
<property type="java.lang.String" value="mysql"/>
</bean>
<!-- 解决参数类型重复问题 -->
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<!-- 此处的index为构造方法的参数的顺序 -->
<property index="0" value="10"/>
<property index="1" value="mysql"/>
</bean>
</beans>
依赖注入方式选择
- 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致nu11对象出现
- 可选依赖使用setter注入进行,灵活性强
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- 自己开发的模块推荐使用setter注入
自动装配(重要)
IoC容器根据bean所依赖的资源在容器中自动査找并注入到bean中的过程称为自动装配
自动装配方式
- 按类型(主要)
- 按名称
- 按构造方法
第一步:方法提供构造方法。
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save(){
System.out.println("BookService Run !");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
第二步:删除自己写的注入,添加autowire
属性
<bean id="bookDao" class="com.angelday.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl" autowire="byType">
</bean>
依赖自动装配特征
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
集合注入
主要了解配置的格式
public class BookServiceImpl {
private int[] array;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
public void setArray(int[] array) {
this.array = array;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
<?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-4.0.xsd">
<bean id="bookService" class="com.angelday.service.impl.BookServiceImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
<!-- 如果内容是引用类型则使用这种写法 -->
<!-- 一般都是简单类型 -->
<!-- <ref bean="beanId"/> -->
</array>
</property>
<property name="list">
<list>
<value>angel</value>
<value>day</value>
<value>hello</value>
</list>
</property>
<property name="set">
<set>
<value>angel</value>
<value>day</value>
<value>hello</value>
</set>
</property>
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="hebei"/>
<entry key="city" value="handan"/>
</map>
</property>
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">hebei</prop>
<prop key="city">handan</prop>
</props>
</property>
</bean>
</beans>
注入第三方Bean
以druid距离
第一步:导坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
第二步:编写配置文件
<?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-4.0.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
</beans>
处理敏感信息
我们发现我们的账号和密码直接写到了xml配置文件中,这显然是不合理的
一般我们是写道properties配置文件中。
第一步:开启context命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
第二步:使用context命名空间,加载指定properties文件
<context:property-placeholder location="classpath:*.properties"/>
第三步:使用${}
读取加载的属性值
<property name="username" value="${jdbc.username}"/>
小结
获取容器方式
方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
方式三:加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");
获取bean的方式
1.使用bean名称获取
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
2.使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
3.使用bean类型获取
BookDao bookDao = ctx.getBean(BookDao.class);
bean相关
<bean
id="bookDao" bean的id
name="dao bookDaoImpl daoImpl" bean的别名
class="com.Angelday.dao.impl.BookDaoImpl" bean类型,静态工厂类,FactoryBean类
scope="singleton" 控制bean的实例数量
init-method="init" 生命周期初始化方法
destroy-method="destory" 生命周期销毁方法
autowire="byType" 自动装配类型
factory-method="getInstance" bean工厂方法,应用于静态工厂或实例工厂
factory-bean="com.itheima.factory.BookDaoFactory"实例工厂
lazy-init="true" 控制bean延迟加载
/>
纯注解开发
引入
前面我们在声明一个被Spring容器管理的Bean时,需要在XML中声明
<bean id="userDao" class="com.angelday.dao.UserDao">
而我们使用注解开发时,只需要想要声明Bean的类中添加一个注解@Component()
并且在括号里添加这个Bean的id
@Component("id")
public class UserDao{
public void save(){
System.out.println("userDao-->run!");
}
}
这样我们只能够声明这是一个被管理的bean,但是Spring容器并不能直接识别到它,所以我们需要创建一个类,来告诉Spring要去哪里找bean我们在根目录下创建一个新的包:config
,用来存放配置类
//这个注解用来声明这是一个Spring的配置类
@Configuration
//这个注解用来告诉Spring需要去哪里扫描bean
@ComponentScan("com.angelday")
public class SpringConfig{
}
注:如果还要使用配置文件,我们要添加
< context:component-scan base-package="com.angelday"/>
创建好这个配置类后,我们就可以删除xml配置文件了。
此时我们在获取容器时,也不再加载配置文件,而是加载配置类
public class App{
public static void main(){
//获取IoC容器,并且传入配置类
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
//获取Bean,使用getBean("id");方法
UserDao userDao = (UserDao)ctx.getBean("userDao");
userDao.save();
}
}
与配置文件对比
注解只是代替了以前的内容
- 原先
xml配置文件
被SpringConfig类
代替 xml格式
写为类中的@Configuration
注解< bean>
标签被@Component
代替id属性
写在@Component("id")
中class属性
写到配置类的@ComponentScan("com.angelday")
- 获取IoC容器的对象
ClassPatjXmlApplicationContext
换为AnnotationConfigApplicationContext
注意:Spring提供了@Component注解的三个衍生注解
注解 | 说明 |
---|---|
@Controller | 表现层bean定义 |
@Service | 业务层bean定义 |
@Repository | 数据层bean定义 |
自动装配
只需要在需要装配的属性前加上@Autowired
并且可以省略
配置文件式开发使用的Setter方法
public class BookService{
@Autowired
private BookDao bookDao;
public void save(){
bookDao.save();
}
}
按类型自动装配:@Autowired
按名称自动装配:@Qualifier(“bean’s id”)
注意:@Qualifier必须配合@Autowired注解使用
注入简单类型
在属性上直接使用@Value()注解
@Repository("userDao")
public class UserDao{
@Value("Zhangsan")
private String name;
}
注入外部Properties
name=zhangsan
在Spring配置类中添加@PropertySource()注解
@Configuration
@ComponentScan("com.angelday")
@PropertySource("classpath:Xxx.properties")
public class SpringConfig{
}
在需要注入的属性前添加@Value()注解
@Repository("userDao")
public class UserDao{
@Value(#{name})
private String name;
}
注入第三方bean
此处还是以druid距离
- 添加一个配置类用来获取要管理的对象
此处以添加Druid
的数据源为例
public class JdbcConfig{
//定义一个方法获取管理的对象
//@Bean表示当前方法返回值是一个bean
@Bean
public DataSource dataSource(){
DruidDataSource dds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/db_name");
ds.setUsername("root");
ds.setPassword("123456");
return dds;
}
}
- 在SpringConfig配置类中导入这个配置类
使用@Import引入
@Configuration
@Improt(JdbcConfig.class)
public class SpringConfig{
}
- 处理敏感信息
上面简单类型数据不应该写在类里,所以可以使用@Value的方式注入简单数据类型
public class JdbcConfig{
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/db_name")
private String url;
@Value("root")
private String userName;
@Value("123456")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource dds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return dds;
}
}
对于引用数据类型,可以直接在方法的形参处添加
public class JdbcConfig{
//假设这个Bean需要依赖与BookDao
@Bean
//直接作为形参传入即可,Spring会自动装配
public DataSource dataSource(BookDao bookDao){
System.out.println(bookDao);
DruidDataSource dds = new DruidDataSource();
return dds;
}
}
- 引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象
AOP
AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构
OOP(object oriented Programming)面向对象编程
作用︰在不惊动原始设计的基础上为其进行功能增强
Spring理念∶无入侵式/无侵入式
核心概念
- 连接点 (JoinPoint):
- 程序执行过程中的任意位置,粒度非常细,可以是执行方法、抛出异常、设置变量等具体的操作点。
- 在 Spring AOP 中,通常理解为方法的执行,因为方法的调用是常见的可被 AOP 切入的连接点。例如,当一个对象的某个方法被调用时,这个方法的执行点就是一个连接点。
- 切入点 (Pointcut):
- 是用来匹配连接点的表达式或规则。
- 在 Spring AOP 中,一个切入点可以有不同的粒度和范围。
- 可以只描述一个具体方法,比如 “com.angelday.dao 包下的 BookDao 接口中的无形参无返回值的 save 方法”,这是非常具体的切入点定义,只有当这个特定的方法被执行时,AOP 才会介入。
- 也可以匹配多个方法,例如 “所有的 save 方法”,这会匹配项目中任何类中的名为 save 的方法;“所有的 get 开头的方法”,只要方法名以 get 开头就会被匹配;“所有以 Dao 结尾的接口中的任意方法”,只要接口名称以 Dao 结尾,其中的任何方法执行都会被视为切入点;“所有带有一个参数的方法”,无论在哪个类中,只要方法有一个参数就符合这个切入点的定义。
- 通知 (Advice):
- 是在切入点处执行的操作,也就是所谓的共性功能。
- 在 Spring AOP 中,功能最终以方法的形式呈现。常见的通知类型有前置通知(Before Advice)、后置通知(After Advice)、环绕通知(Around Advice)等。
- 前置通知在目标方法执行之前执行,可以用于一些准备工作,如参数验证、日志记录等。
- 后置通知在目标方法执行之后执行,可以用于处理方法的返回结果、记录方法执行时间等。
- 环绕通知可以完全控制目标方法的执行,包括在目标方法执行前后执行额外的代码,甚至可以决定是否执行目标方法。
- 通知类:
- 定义通知的类,通常包含一个或多个通知方法。这些方法会在特定的切入点被触发执行,实现 AOP 的横切关注点分离。
- 通知类可以通过注解或在 XML 配置文件中进行定义,以便被 Spring AOP 框架识别和管理。
- 切面 (Aspect):
- 描述通知与切入点的对应关系。一个切面是一个模块化的横切关注点的实现,它将特定的通知应用到一组匹配的切入点上。
- 例如,定义一个日志记录的切面,可以将前置通知(记录方法开始执行的日志)和后置通知(记录方法执行结束的日志)应用到多个切入点,如特定包下的所有业务方法。
- 在 Spring 中,可以通过注解或 XML 配置来定义切面,使得 AOP 功能更加易于管理和维护。