spring Ioc

1 spring中的概念

IoC:Inverse of Control,控制反转。对象的创建权力由程序反转给Spring框架。
DI:Dependency Injection,依赖注入。在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!
AOP:Aspect Oriented Programming,面向切面编程。在不修改目标对象的源代码情况下,增强IoC容器中Bean的功能。
Spring容器:指的就是IoC容器。

ioc和di是同一个概念的两个说法,aop是动态代理在spring中的名字

2 Ioc原理分析

IoC即将bean交由IoC容器管理

2.1 bean

Ioc容器管理的对象叫做bean,默认情况下,采用无参的构造函数创建

2.1.1 bean属性

id:bean在ioc容器中的唯一标识,用于获取bean
class:指定类的全限定名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围

  • singleton :默认值,单例的(在整个容器中只有一个对象)
  • prototype :多例的.
  • request :将Spring 创建的 Bean 对象存入到 request 域中.
  • session :将Spring 创建的 Bean 对象存入到 session 域中.
  • global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.

init-method:指定bean的初始化方法
destory-method:指定bean的销毁方法

2.1.2 scope

1 单例scope="singleton"
一个应用只有一个对象的实例。它的作用范围就是整个引用。
生命周期:

  • 创建:当应用加载,创建容器时,对象就被创建了。
  • 销毁:当应用卸载,销毁容器时,对象就被销毁了

2 多例对象:scope="prototype"
每次访问对象时,都会重新创建对象实例。
生命周期:

  • 创建:当使用对象时,创建新的对象实例。
  • 销毁:当对象长时间不用时,被 java 的垃圾回收器回收了。

2.1.3 bean实例化

实例化bean的三种方式:无参构造方法、静态工厂、动态工厂

2.2 BeanFactory

BeanFactory接口提供了一种更先进的配置机制来管理任意类型的对象。
ApplicationContext 是 BeanFactory 的一个子接口。

2.3 BeanFactory子接口:只能提供单个bean

  • AutowireCapableBeanFactory子接口:可以将第三方的bean进行自动装配
  • ConfigurableBeanFactroy子接口:对beanFactory实现配置管理
  • ListableBeanFactory子接口:提供beanFactory容器内bean实例全部获取并遍历的功能,需要预先加载所有bean定义的工厂需要实现这个接口

3 spring 基于xml使用

目录结构
在这里插入图片描述
在pom.xml中引入相关依赖

<properties>
	<spring-version>5.1.2.RELEASE</spring-version>
</properties>

<dependencies>
        <!-- 引入 spring core-->
   <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-core</artifactId>
       <version>${spring-version}</version>
   </dependency>

        <!-- spring beans -->
   <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring-version}</version>
    </dependency>
	  <!-- spring context -->
    <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context</artifactId>
         <version>${spring-version}</version>
     </dependency>

     <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring-version}</version>
      </dependency>

        <!-- junit 测试 -->
	<dependency>
       <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4</version>
    </dependency>
        <!-- spring junit 整合测试 -->
	<dependency>
       <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring-version}</version>
    </dependency>
	<!-- inject 注解 -->
    <dependency>
         <groupId>javax.inject</groupId>
         <artifactId>javax.inject</artifactId>
         <version>1</version>
     </dependency>   

3.1 IoC基于XML的使用

ApplicationContext是能够保持bean定义以及相互依赖关系的高级工厂接口

3.1.1 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"
       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">
    <!-- bean definitions here -->
    <!-- id:唯一标识 ,可以通过该标识获取java实例 -->
    <!-- class:配置要实例化的java类全类名 -->
    <bean id="userService" class="com.cc.service.UserServiceImpl" />
</beans>

3.1.2 UserDao 和UserSeviceImpl

@Repository
public class UserDao {
    public void saveUser( User user){
        System.out.println("userDao: saveUser:id为"+user.getId()+", name为:"+user.getName());
    }
}
//@Service
public class UserServiceImpl implements UserService {
    User user;

    @Autowired
    //@Resource
    //@Inject
    private UserDao userDao;

    public UserServiceImpl() { }

    // 为了使用构造函数注入+ Proerties配置 设计
    public UserServiceImpl(User user) {
        this.user = user;
    }
	
	 // 为了使用构造函数注入+ Proerties配置 设计
    @Override
    public void saveUser() {
        userDao.saveUser(user);
    }

    @Override
    public void saveUser(User user) {
//        System.out.println("保存用户:id为"+id+",name为"+name+"   Service实现");
        userDao.saveUser(user);
    }

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

3.1.2 测试

public class IoCTest {
    @Test
    public void testToC1(){
        //创建
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器中获取bean的实例
        //方式1:根据类型容器中获取bean实例
        UserService service1 = context.getBean(UserService.class);
        service1.saveUser();
        //方式2 根据bean的id从容器中获取bean实例
        UserService service2= (UserService)context.getBean("userService");
        service2.saveUser();
    }
}

输出

保存用户:id为0,name为null   Service实现
保存用户:id为0,name为null   Service实现

3.2 DI基于xml的配置

3.2.1 使用构造函数进行注入

使用类中的构造函数,给成员变量赋值。
类中需要提供一个对应参数列表的构造函数。
涉及的标签:constructor-arg

  • index:指定参数在构造函数参数列表的索引位置
  • name:指定参数在构造函数中的名称
  • value:它能赋的值是基本数据类型和 String 类型
  • ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
 <!-- Ioc 管理 user bean -->
<bean id="user" class="com.cc.pojo.User">
	<!-- 构造函数注入 -->
     <constructor-arg name="id" value="1111"/>
     <constructor-arg name="name" value="userBean" />
 </bean>
 <!-- Ioc 配置 UserDao-->
 <bean id="userDao" class="com.cc.dao.UserDao" />

 <!-- Ioc 管理 UserSevice -->
 <bean id="userServiceImpl" class="com.cc.service.UserServiceImpl">
     <constructor-arg name="user" ref="user" />
     <!-- set方法注入,在UserSevicesImpl中后setUserDao 方法 -->
     <property name="userDao" ref="userDao"/>
 </bean>

输出

userDao: saveUser:id为1111, name为:userBean

3.2.2 使用set方法进行注入

set方法注入又分为手动装配方式注入和自动装配方式注入。
手动装配方式(XML方式):

  • 通过bean标签的子标签property来完成
  • 需要在类中指定setter方法。

3.2.3 使用p名称空间注入

<bean id="userService" class="com.cc.service.UserServiceImpl" p:name="wangwu" p:userDao-ref="userDao" />

本质上还是使用的set方法进行的依赖注入,对应属性需要有set方法

4 spring基于注解和xml混合使用

4.1 IoC应用

applicationContext.xml

<!-- 开启注解扫描 -->
<context:component-scan base-package="com.cc"/>

@Service和@Responsity注解

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;//不再需要set方法
 }
 
@Repository
public class UserDao {
    public void saveUser( User user){
        System.out.println("userDao: saveUser:id为"+user.getId()+", name为:"+user.getName());
    }
}

4.2 注解

@Component

  • 作用:
    把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
  • 属性:
    value:指定 bean 的 id。
    如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。

@Controller、@Service、@Repository注解

  • 他们三个注解都是针对@Component的衍生注解
  • 他们的作用及属性都是一模一样的。他们只不过是提供了更加明确的语义化。
    @Controller:一般用于表现层的注解。
    @Service:一般用于业务层的注解。
    @Repository:一般用于持久层的注解。
  • 细节:如果注解中有且只有一个属性要赋值时,且名称是 value,value 在赋值是可以不写。

4.3 DI注解

相当于:

4.3.1 @Authowired

  • @Autowired是spring自带的注解
  • 默认按类型装配(byType)
  • 默认情况下要求依赖对象必须存在,如果需要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)
  • 如果我们想按名称装配(byName)可以结合@Qualifier注解进行使用

4.3.2 @Qualifier

  • 在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。
  • 它在给字段注入时不能独立使用,必须和@Autowire 一起使用;
  • 但是给方法参数注入时,可以独立使用。

4.3.3 @Resource

  • 属于J2EE JSR250规范的实现,用法和@Authowired 类似
  • 默认按名称装配(byName),可以通过@Resource的name属性指定名称
  • 如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,当找不到与名称匹配的bean时才按照类型进行装配。
  • 但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
  • 推荐使用@Resource注解,因为这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

4.3.4 @Inject

  • @Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named;
  • @Inject是JSR330中的规范,需要导入javax.inject.Inject;实现注入。
  • @Inject可以作用在变量、setter方法、构造函数上。

4.3.5 @Value

  • 给基本类型和String类型注入值
  • 可以使用占位符获取属性文件中的值。
    user.properties
user.id=100
user.name=configUser

applicationContext.xml

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

UserServiceImp

@Value("${user.id}")//user.id是properties文件中的key
private int id;
@Value("${user.name}")
private String name;

4.3.6 @Scope

 @Test
public void testToC1(){
    //创建
    ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
    //从容器中获取bean的实例
    //方式1:根据类型容器中获取bean实例
    UserService service1 = context.getBean(UserService.class);
    System.out.println(service1);
    //service1.saveUser();
    //方式2 根据bean的id从容器中获取bean实例
    UserService service2= (UserService)context.getBean("userServiceImpl");
    //System.out.println(service2);
    service2.saveUser();
}

默认作用范围的输出

com.cc.service.UserServiceImpl@799d4f69
com.cc.service.UserServiceImpl@799d4f69

添加@Scope 标签


多例模式时输出

com.cc.service.UserServiceImpl@70beb599
com.cc.service.UserServiceImpl@4e41089d

4.3.7 @PostConstruct 和@PreDestroy

相当于

<bean id="" class="" init-method="" destroy-method="" />

5 比较xml和注解方式

  • 注解
    • 配置简单,维护方便(我们找到类,就相当于找到了对应的配置)
    • 适用场景:bean由自己实现
  • xml
    • 修改时,不用改源码。不涉及重新编译和部署。
    • 适用场景:bean来自第三方
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值