Spring-IOC(控制反转)

一、spring概述

1.1 框架概述

框架是一个封装了很多功能和模块的程序的半成品。
可以理解为是一个由很多工具类组合而成的一个工具包。
框架可以提高我们的开发效率

1.2 Spring是什么

Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架。是Java开发的灵魂框架。
Spring有两大内核:
IOC(Inverse Of Control:控制反转)
AOP(Aspect Oriented Programming:面向切面编程)

1.3 Spring功能

IOC:控制反转,其实就是把对象的创建权,交给spring,由Spring负责给我们创建对象

DI:   依赖注入,其实就是给对象的成员变量赋值。

AOP:面向切面编程,底层就是动态代理

事务: Spring提供了声明式事务,也就是说,我们可以通过配置的方式来添加事务。

二、 入门案例

2.1 Spring程序开发步骤

①导入 Spring 开发的基本包坐标(5.1.9.release)
②创建Spring核心配置文件
③在 Spring 配置文件中配置要创建的对象
④通过spring获取资源(获取创建的对象)

2.2 案例实现

① 导入坐标

<!--spring核心-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>

② 创建Spring核心配置文件,③配置

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 1.创建spring控制的资源(让spring帮忙创建该类的对象)-->
    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
    
</beans>

④ 通过spring获取资源(获取创建的对象)

public class UserApp {
    public static void main(String[] args) {
        //1.加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        //3.调用方法
        userService.save();
    }
}

三、IOC配置-XML格式

3.1 Bean标签基本配置

作用:定义spring中的资源,受此标签定义的资源将受到spring控制

格式:

<beans>
	<bean 属性名="属性值" ></bean>
</beans>

3.2 常见属性

id:Bean实例在Spring容器中的唯一标识,通过id值获取bean

class:Bean的类型, spring创建的就是该类的对象

name:Bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名

ps:其他属性

3.3.1 scope
格式:

<bean scope="singleton"></bean>

取值:

  • singleton:设定创建出的对象保存在spring容器中,是一个单例的对象,
  • prototype:设定创建出的对象保存在spring容器中,是一个多例的对象

3.4 对象创建方式

1) 使用无参构造方法实例化

默认调用无参构造方法创建对象,如果bean中没有默认无参构造函数,将会创建失败

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

2) 工厂静态方法实例化
工厂静态方法实例化, 指的是在创建对象的时候,是通过调用某个类的静态方法才能创建对象.
例如:LocalDate now = LocalDate.now();

<!-- LocalDate now = LocalDate.now();  -->
<bean id="now" class="java.time.LocalDate" factory-method="now"/>

3) 工厂实例方法实例化
工厂实例方法实例化, 指的是在创建对象的时候, 需要通过其他类的对象才能创建对象.

<!-- LocalDate now = LocalDate.now();  -->
<bean id="now" class="java.time.LocalDate" factory-method="now"/>

<!-- DayOfWeek dayOfWeek = now.getDayOfWeek();  -->
<bean id="dayOfWeek" factory-bean="now" factory-method="getDayOfWeek"/>

四、 依赖注入-DI

4.1 概述
依赖注入(Dependency Injection):是SpringIOC的具体体现,简单来说,就是给对象的属性赋值

4.2 Bean的依赖注入方式

4.2.1 Set方法赋值(常用)
①在UserServiceImpl中添加setUserDao方法

public class UserServiceImpl implements UserService {
    private UserDao userDao;
 
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;  
    } 
    
    @Override    
    public void save() {      
   		 userDao.save();
	}
}

②配置Spring容器调用set方法进行注入

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
    <!-- 使用setUserDao方法,把userDao对象,注入userService中 -->
	<property name="userDao" ref="userDao"/>
</bean>

4.2.2 构造方法赋值

①在类中提供有参构造

public class UserServiceImpl implements UserService {	
    private UserDao userDao;

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void save() {
        userDao.save();
    }
 }

②配置Spring容器调用有参构造时进行注入

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
    <!-- 使用构造方法,把userDao对象,注入userService中 -->
    <constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>

4.3 集合类型数据注入

  1. list
<property name="al">
    <list>
        <value>itheima</value>
        <value>66666</value>
        <!--如果集合元素是对象,则可以注入对象(直接创建新对象)-->
        <bean class="com.itheima.domain.User"/>
        <!--如果集合元素是对象,则可以注入对象(引入已经创建的对象)-->
        <ref bean="u1"/>
    </list>
</property>
  1. rops
<property name="properties">
    <props>
        <prop key="name">itheima666</prop>
        <prop key="value">666666</prop>
    </props>
</property>
  1. array
<property name="arr">
    <array>
        <value>123456</value>
        <value>66666</value>
    </array>
</property>
  1. set
 <property name="hs">
     <set>
         <value>itheima</value>
         <value>66666</value>
     </set>
</property>
  1. map
<property name="hm">
    <map>
        <entry key="name" value="itheima66666"/>
        <entry key="value" value="6666666666"/>
    </map>
</property>

五、 其他

5.1 引入properties文件

语法:

<context:property-placeholder location="classpath:filename.properties">

获取数据:

<property name="propertyName" value="${propertiesName}"/>
  • 注意:如果需要加载所有的properties文件,可以使用*.properties表示加载所有的properties文件
  • 注意:读取数据使用${propertiesName}格式进行,其中propertiesName指properties文件中的属性名

5.2 引入其他配置文件

如果当前项目有多个配置文件, 则可以:
1.在主配置文件中引入其他配置文件
2.在加载时,直接加载多个配置文件

引入其他配置文件

<import resource="被引入配置文件的路径"/>

直接加载多个配置文件

new ClassPathXmlApplicationContext("config1.xml","config2.xml");

注意:

  • 同id的bean,后定义的覆盖先定义的
  • 导入配置文件可以理解为将导入的配置文件复制粘贴到对应位置
  • 导入配置文件的顺序与位置不同可能会导致最终程序运行结果不同

5.3 ApplicationContext对象的获取

//加载配置文件,获取Spring核心容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

//加载配置文件,获取Spring核心容器, 一般不用
ApplicationContext ac2 = new FileSystemXmlApplicationContext("配置文件绝对路径");

//加载配置类, 获取Spring核心容器, 用于注解开发
ApplicationContext ac3 = new AnnotationConfigApplicationContext(配置类.class);

5.4 实例对象的获取

//加载配置文件,获取Spring核心容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

//获取Spring核心容器中,id叫做"userService"的对象
UserService userService = (UserService)ac.getBean("userService");
//获取Spring核心容器中,类型是"UserService"的对象
UserService userService = ac.getBean(UserService.class);
//获取Spring核心容器中,,id叫做"userService"的,类型是"UserService"的对象
UserService userService = ac.getBean("userService",UserService.class);

扩展知识块

一、注解开发

1.1 意义

Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。

1.2 启动注解功能

位置: 在spring的配置文件中进行开启

语法: <context:component-scan base-package="包名"/>

说明:

  • 在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描
  • 扫描过程是以文件夹递归迭代的形式进行的
  • 扫描过程仅读取合法的java文件
  • 扫描时仅读取spring可识别的注解
  • 扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器

注意:

  • 无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同
  • 从加载效率上来说注解优于XML配置文件

.3 常用注解

1.3.1 创建对象的注解


@Component:使用在类上,用于实例化Bean

@Controller:使用在web层类上,用于实例化Bean

@Service:使用在service层类上,用于实例化Bean

@Repository:使用在dao层类上用于,实例化Bean

案例:

@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
    	System.out.println("save running... ...");
    }
}
//上述四个注解作用一样,也就是说,这里同样可以写其他三个注解,但约定俗成,Dao层一般使用Repository

1.3.2 作用范围的注解

@Scope

两个取值:“prototype” -> 多例的,“singleton” -> 单例的(默认)

案例:

@Scope("singleton")
public class UserDaoImpl implements UserDao {
   //此处省略代码
}

1.3.3 初始化注解(了解)

@PostConstruct

被标注的方法,在对象被创建的时候执行

@PreDestroy

被标注的方法,在对象被销毁的时候执行

案例:

@PostConstruct
public void init(){
	System.out.println("初始化方法....在对象被创建的时候执行....");
}
@PreDestroy
public void destroy(){
	System.out.println("销毁方法....在对象被销毁的时候执行....");
}

1.3.4 第三方对象注解-@Bean
作用:

 使用在方法上,Spring会自动执行该方法,并把方法返回的对象,存储在spring容器中

范例:

@Bean("dataSource")
public DataSource getDataSource() throws PropertyVetoException { 
    ComboPooledDataSource ds = new ComboPooledDataSource(); 
    ds.setDriverClass(driver);
    ds.setJdbcUrl(url);
    ds.setUser(username);
    ds.setPassword(password);
    return ds;
} 

说明:

  • 因为第三方bean无法在其源码上进行修改,使用@Bean解决第三方bean的引入问题
  • 该注解用于替代XML配置中的静态工厂与实例工厂创建bean,不区分方法是否为静态或非静态
  • @Bean所在的类必须被spring扫描加载,否则该注解无法生效

相关属性:

  • value(默认):定义bean的访问id

1.3.5 依赖注入的注解

@Autowired

根据类型依赖注入,如果找到多个,则根据变量名依赖注入

@Qualifier@Autowired一起使用,用于根据名称进行依赖注入

@Value

注入普通属性。一般用于获取properties中的key,然后注入成员变量中

案例:使用@Autowired对引用类型进行注入

@Service("userService")
public class UserServiceImpl implements UserService {
    
    @Autowired		//根据类型依赖注入,如果找到多个,则根据变量名userDao依赖注入
    private UserDao userDao;
    
    @Override
    public void save() {       
   	  userDao.save();
    }
}

使用@Value进行字符串的注入

@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Value("注入普通数据")	  //注入普通数据
    private String str;
    @Value("${jdbc.driver}")  //获取已经加载到容器中的properties中的指定的键,并注入
    private String driver;
    
    @Override
    public void save() {
        System.out.println(str);
        System.out.println(driver);
    }
}

1.4 其他注解

1.4.1 @Primary

作用:

	定义在类上, 当@Autowired按类型装配时, 默认先装配该类对象. 提高该类优先级

范例:

@Primary
public class ClassName{}

说明:多个@Primary会导致优先级设置无效

1.4.2 @Inject与@Named

@Inject与@Named是JSR330规范中的注解,功能与@Autowired和@Qualifier完全相同,适用于不同架构场景

1.4.3 @Resource
说明:

  • @Resource是JSR250规范中的注解,可以简化书写格式
  • @Resource相当于"@Autowired + @Qualifier"

属性:

  • name:设置注入的bean的id
  • type:设置注入的bean的类型,接收的参数为Class类型

二、纯注解开发

2.1 概述
Spring所谓的纯注解开发,其实就是完全摒弃Spring的配置文件, 使用注解完全替代其对应功能。

2.2 对应注解

@Configuration

用于指定当前类是一个 Spring配置类,当创建容器时会从该类上加载注解

@ComponentScan

用于指定 Spring 在初始化容器时要扫描的包。

@PropertySource

用于加载.properties   文件中的配置

@Import

用于导入其他配置类

2.2 新注解详解
2.2.1 @Configuration

用于指定 Spring 在初始化容器时要扫描的包。
相当于xml配置时的<context:component-scan base-package=“com.itheima”/>

@Configuration
@ComponentScan("com.itheima")		
public class SpringConfiguration {
    
}

2.2.3 @Import
用于导入其他的配置类

相当于xml配置时的

@Configuration
@ComponentScan("com.itheima")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}

2.2.4 @PropertySource

用于properties配置文件

相当于xml配置时的<context:property-placeholder location=“classpath:jdbc.properties”/>

@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
    @Value("${jdbc.driver}")
    private String driver;
    
    @Value("${jdbc.url}")
    private String url;
    
    @Value("${jdbc.username}")
    private String username;
    
    @Value("${jdbc.password}")
    private String password;
}

2.2.5 加载配置类

@Test
public void testAnnoConfiguration() throws Exception {
    //根据配置类SpringConfiguration.class,获取Spring的核心容器
	ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    
    //获取userService对象
    UserService userService = (UserService)ac.getBean("userService");
    userService.save();
    
    //获取dataSource对象
    DataSource dataSource = (DataSource)ac.getBean("dataSource");
    Connection connection = dataSource.getConnection(); 
    System.out.println(connection);
}

三、Bean加载控制

3.1 @DependsOn

作用:

	定义在类或者方法上,  用来控制bean的加载顺序,使其在指定bean加载完毕后再加载

范例:@DependsOn("beanId") public class ClassName { }

说明:

  • 配置在方法上,使@DependsOn指定的bean优先于@Bean配置的bean进行加载
  • 配置在类上,使@DependsOn指定的bean优先于当前类中所有@Bean配置的bean进行加载
  • 配置在类上,使@DependsOn指定的bean优先于@Component等配置的bean进行加载

场景:

  • 微信订阅号,发布消息和订阅消息的bean的加载顺序控制
  • 双11活动期间,零点前是结算策略A,零点后是结算策略B,策略B操作的数据为促销数据。策略B加载顺序与促销数据的加载顺序

3.2 Order

作用:

	定义在类上, 用来控制配置类的加载顺序, 让配置类按照指定的序号进行加载

范例:@Order(1) public class SpringConfigClassName { }
场景:

	多个种类的配置出现后,优先加载系统级的,然后加载业务级的,避免细粒度的加载控制

3.3 @Lazy

作用:

	定义在类或方法上, 控制bean的加载时机,使其延迟加载

范例:@Lazy public class ClassName { }

场景:

程序灾难出现后对应的应急预案处理是启动容器时加载时机

四、Spring整合Junit

4.1 概述

在原来的代码中,在测试类中,不能正常使用依赖注入。
如果想让测试类中,也可以使用依赖注入,则需要Spring整合Junit

4.2 Spring集成Junit步骤

①导入spring集成Junit的坐标

②使用@Runwith注解替换原来的运行期

③使用@ContextConfiguration指定配置文件或配置类

④使用@Autowired注入需要测试的对象

⑤创建测试方法进行测试

4.3 Spring集成Junit代码实现

①导入spring集成Junit的坐标

<!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

②使用@Runwith表示,当前测试类被spring接管

@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunitTest {
}

③使用@ContextConfiguration指定配置文件或配置类

@RunWith(SpringJUnit4ClassRunner.class)
//加载spring核心配置文件
//@ContextConfiguration(value = {"classpath:applicationContext.xml"})
//加载spring核心配置类
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
}

④使用@Autowired注入需要测试的对象

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
    
    @Autowired
    private UserService userService;
}

⑤创建测试方法进行测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void testUserService(){
   	   userService.save();
    }
}

五、 Spring组件扫描

5.1 XML配置(只扫描service)

方式1:

<context:component-scan base-package="com.itheima.service"/>	

方式2:

<context:component-scan base-package="com.itheima">
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

方式3

<context:component-scan base-package="com.itheima" use-default-filters="false">
	<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>

5.2 注解配置(只扫描service)

方式1

@ComponentScan("com.itheima.service")

方式2

@ComponentScan(value = "com.itheima",excludeFilters = {
    @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)
})

方式3

@ComponentScan(value = "com.itheima",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Service.class)
},useDefaultFilters = false)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值