Spring核心之IOC

Spring体系结构

Spring 框架是一个分层架构,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation和测试部分,如下图所示:

面向接口编程

  • 结构设计中,分清层次及调用关系,每层只向外(上层)提供一组功能接口,各层间仅依赖接口而非实现类。
  • 接口实现的变动不影响各层间的调用,这一点在公共服务中尤为重要。
  • “面向接口编程”中的“接口”是用于隐藏具体实现和实现多态性的组件。

IOC

  • 什么是IOC?
    • IOC:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护。
    • DI(依赖注入)是其一种实现方式
    • 目的:创建对象并且组装对象之间的关系
  • 实例

    • 提供UserService接口和实现类
    • 获得UserService实现类的实例
    • 由Spring创建对象实例–> IoC 控制反转(Inverse of Control)

      public interface UserService {
          public void addUser();
      }
      
      public class UserServiceImpl implements UserService {
      
          @Override
          public void addUser() {
              System.out.println("tyshawn");
          }
      }
      
      public class TestIOC {
          @Test
          public void test() throws Exception {
              String xmlPath = "org/a/IOC/beans.xml";
      
              ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
              UserService service = (UserService) context.getBean("userServiceId");
              service.addUser(); //tyshawn
          }
      }
      
      <beans
          <!--IOC-->
          <bean id="userServiceId" class="org.a.IOC.UserServiceImpl"> </bean>
      </beans>
      

DI

  • 依赖:一个对象需要使用另一个对象
  • 注入:通过setter方法进行另一个对象实例设置。
  • 模拟spring执行过程:

    • 创建service实例:BookService bookService = new BookServiceImpl() –>IoC
    • 创建dao实例:BookDao bookDao = new BookDaoImple() –>IoC
    • 将dao设置给service:bookService.setBookDao(bookDao); –>DI

      public interface BookDao {
          public void addBook();
      }
      
      public class BookDaoImpl implements BookDao {
          @Override
          public void addBook() {
              System.out.println("add book");
          }
      }
      
      public interface BookService {
          public void addBook();
      }
      
      public class BookServiceImpl implements BookService{
          private BookDao bookDao;
          public void setBookDao(BookDao bookDao) {
              this.bookDao = bookDao;
          }
      
          @Override
          public void addBook() {
              this.bookDao.addBook();
          }
      }
      
      public class TestDI {
          @Test
          public void test() throws Exception {
              String xmlPath = "org/b/DI/beans.xml";
      
              ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
              BookService service = (BookService) context.getBean("BookServiceId");
              service.addBook(); //add book
          }
      }
      
      <beans
          <!--控制反转-->
          <bean id="BookServiceId" class="org.b.DI.BookServiceImpl">
              <!--依赖注入-->
              <property name="bookDao" ref="BookDaoId"></property>
          </bean>
      
          <bean id="BookDaoId" class="org.b.DI.BookDaoImpl"></bean>
      </beans>
      

核心API

  • BeanFactory:这是一个工厂,用于生成任意bean。采取延迟加载,第一次getBean时才会初始化Bean。
  • ApplicationContext:是BeanFactory的子接口,功能更强大。(国际化处理、事件传递、Bean自动装配、各种不同应用层的Context实现)。当配置文件被加载,就进行对象实例化。
  • ClassPathXmlApplicationContext:用于加载classpath(类路径、src)下的xml
  • FileSystemXmlApplicationContext:用于加载指定盘符下的xml

    @Test
    public void demo02(){
        //使用BeanFactory  --第一次条用getBean实例化
        String xmlPath = "org/a/IOC/beans.xml";
    
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(xmlPath));
    
        BookService bookService = (BookService) beanFactory.getBean("bookServiceId");
    
        bookService.addBook();
    }
    

Bean实例化方式

3种bean实例化方式:默认构造、静态工厂、实例工厂

默认构造:

<bean id="" class="">  必须提供默认构造

静态工厂:用于生成实例对象,所有的方法必须是static

<bean id=""  class="工厂全限定类名"  factory-method="静态方法">

public interface UserService {
    public void addUser();
}

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("tyshawn");
    }
}

public class MyBeanFactory {
    /**
     * 创建实例,方法必须是静态的
     */
    public static UserServiceImpl createService(){
        return new UserServiceImpl();
    }
}

public class TestStaticFactory {
    @org.junit.Test
    public void test() throws Exception {
        String xmlPath = "org/c/staticfactory/beans.xml";

        ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
        UserService service = (UserService) context.getBean("userServiceId");
        service.addUser(); //tyshawn
    }
}

<beans
    <!--将静态工厂创建的实例交予spring
        factory-method 确定静态方法名
        在实际开发中Factory类已写好,直接调用
    -->
    <bean id="userServiceId" class="org.c.staticfactory.MyBeanFactory" factory-method="createService"> </bean>
</beans>

实例工厂:必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是“非静态”的。

public interface UserService {
    public void addUser();
}

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("tyshawn");
    }
}

public class MyBeanFactory {
    /**
     * 创建实例
     */
    public UserServiceImpl createService(){
        return new UserServiceImpl();
    }
}

public class TestFactory {
    @org.junit.Test
    public void test() throws Exception {
        String xmlPath = "org/d/factory/beans.xml";

        ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
        UserService service = (UserService) context.getBean("userServiceId");
        service.addUser();
    }
}

<beans
        <!--
        获得UserService
        factory-bean确定工厂
        factory-method确定工厂方法
    -->
    <bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createService"> </bean>

    <!--创建工厂实例-->
    <bean id="myBeanFactoryId" class="org.d.factory.MyBeanFactory" ></bean>
</beans>

Bean种类

  • 普通bean:之前操作的都是普通bean。< bean id=”” class=”A”> ,spring直接创建A实例,并返回
  • FactoryBean:是一个特殊的bean,具有工厂生成对象能力,只能生成特定的对象。bean必须使用 FactoryBean接口,此接口提供方法 getObject() 用于获得特定bean。< bean id=”” class=”FB”> 先创建FB实例,使用调用getObject()方法,并返回方法的返回值

    FB fb = new FB();
    return fb.getObject();
    
  • BeanFactory 和 FactoryBean 对比?
    • BeanFactory:工厂,用于生成任意bean。
    • FactoryBean:特殊bean,用于生成另一个特定的bean。例如:ProxyFactoryBean ,此工厂bean用于生产代理。< bean id=”” class=”….ProxyFactoryBean”> 获得代理对象实例。AOP使用。

作用域

用于确定spring创建bean实例个数

public interface UserService {
    public void addUser();
}

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("tyshawn");
    }
}

public class TestFactory {
    @org.junit.Test
    public void test() throws Exception {
        String xmlPath = "org/f/scope/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = applicationContext.getBean("userServiceId" ,UserService.class);
        UserService userService2 = applicationContext.getBean("userServiceId" ,UserService.class);

        System.out.println(userService);
        System.out.println(userService2);
    }
}

<beans
    <bean id="userServiceId" class="org.f.scope.UserServiceImpl"
        scope="singleton"  ></bean>
</beans>

生命周期

初始化和销毁
目标方法执行前和执行后,将进行初始化和销毁。

<bean id="" class="" init-method="初始化方法名称"  destroy-method="销毁的方法名称">

public interface UserService {
    public void addUser();
}

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("tyshawn");
    }
    public void myInit(){
        System.out.println("初始化");
    }
    public void myDestroy(){
        System.out.println("销毁");
    }
}

public class TestFactory {
    @org.junit.Test
    public void test() throws Exception {
        String xmlPath = "org/g/lifecycle/beans.xml";
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService) applicationContext.getBean("userServiceId");
        userService.addUser();

        /*执行销毁方法要求:
        * 1.容器必须close
        * 2.必须是单例的
        * */

//      使用反射关闭容器
//      applicationContext.getClass().getMethod("close").invoke(applicationContext);

        applicationContext.close();
    }
}

<beans
    <!--  
        init-method 用于配置初始化方法,准备数据等
        destroy-method 用于配置销毁方法,清理资源等
    -->
    <bean id="userServiceId" class="org.g.lifecycle.UserServiceImpl"
        init-method="myInit" destroy-method="myDestroy" ></bean>
</beans>

结果:
    初始化 
    e_lifecycle add user 
    销毁

Spring注入

Spring注入是指在启动Spring容器加载bean配置的时候,完成对变量的赋值行为。
注入方式有:构造注入、Setter注入、p命名空间、SpEL

构造注入

public class User {
    private Integer uid;
    private String username;
    private Integer age;

    public User(Integer uid, String username) {
        this.uid = uid;
        this.username = username;
    }

    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }

    //getters、setters、toString
}

public class TestCons {
    @org.junit.Test
    public void test() throws Exception {
        String xmlPath = "org/e/xml/DI_constructor/beans.xml";

        ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
        User user = (User) context.getBean("userId");
        System.out.println(user);
    }
}

<beans
    <!-- 构造方法注入
            * <constructor-arg> 用于配置构造方法的一个参数argument
                name :参数的名称
                value:设置普通数据
                ref:引用数据,一般是另一个bean id值

                index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。
                type :确定参数类型
            例如:使用名称name
                <constructor-arg name="username" value="jack"></constructor-arg>
                <constructor-arg name="age" value="18"></constructor-arg>
            例如2:【类型type 和  索引 index】
                <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
                <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
    -->
    <bean id="userId" class="org.e.xml.DI_constructor.User">
        <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
        <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
    </bean>
</beans>

Setter注入

public class Person {

    private String pname;
    private Integer age;

    private Address homeAddr;       //家庭地址
    private Address companyAddr;    //公司地址

    //getters、setters、toString
}

public class Address {
    private String addr;    //地址信息
    private String tel;     //电话

    //getters、setters、toString
}

public class TestSetter {
    @org.junit.Test
    public void test() throws Exception {
        String xmlPath = "org/e/xml/DI_setter/beans.xml";

        ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
        Person person = (Person) context.getBean("personId");
        System.out.println(person);
    }
}

<beans
    <bean id="personId" class="org.e.xml.DI_setter.Person">
        <property name="pname" value="Tom"></property>
        <property name="age">
            <value>22</value>
        </property>
        <property name="homeAddr" ref="homeAddrId"></property>
        <property name="companyAddr">
            <ref bean="companyAddrId"></ref>
        </property>
    </bean>

    <bean id="homeAddrId" class="org.e.xml.DI_setter.Address">
        <property name="addr" value="beijing"></property>
        <property name="tel" value="120"></property>
    </bean>

    <bean id="companyAddrId" class="org.e.xml.DI_setter.Address">
        <property name="addr" value="shanghai"></property>
        <property name="tel" value="119"></property>
    </bean>
</beans>

P命令空间

  • 对“setter方法注入”进行简化,替换< property name=”属性名”>,而是在< bean p:属性名=”普通值” p:属性名-ref=”引用值”>
  • p命名空间使用前提,必须添加命名空间

    public class Person {
    
        private String pname;
        private Integer age;
    
        private Address homeAddr;       //家庭地址
        private Address companyAddr;    //公司地址
    
        //getters、setters、toString
    }
    
    public class Address {
        private String addr;    //地址信息
        private String tel;     //电话
    
        //getters、setters、toString
    }
    
    public class TestSetter {
        @org.junit.Test
        public void test() throws Exception {
            String xmlPath = "org/e/xml/DI_p/beans.xml";
    
            ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
            Person person = (Person) context.getBean("personId");
            System.out.println(person);
        }
    }
    
    <beans
        <!--对property进行简化-->
        <bean id="personId" class="org.e.xml.DI_p.Person"
              p:pname="Tom" p:age="22" p:homeAddr-ref="homeAddrId"
              p:companyAddr-ref="companyAddrId">
        </bean>
    
        <bean id="homeAddrId" class="org.e.xml.DI_p.Address"
              p:addr="beijing" p:tel="120">
        </bean>
    
        <bean id="companyAddrId" class="org.e.xml.DI_p.Address"
              p:addr="shanghai" p:tel="119">
        </bean>
    </beans>
    

SpEL

对< property>进行统一编程,所有的内容都使用value。

public class Customer {

    private String cname = "jack";
    private Double pi ;// = Math.PI;

    //getters、setters、toString
}

public class TestSpEL {
    @Test
    public void test(){
        String xmlPath = "org/e/xml/DI_spel/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        Customer customer = (Customer) applicationContext.getBean("customerId");
        System.out.println(customer);
    }
}

<beans
      <bean id="customerId" class="org.e.xml.DI_spel.Customer">
          <property name="cname" value="#{'Tom'}"></property>
          <property name="pi" value="#{T(java.lang.Math).PI}"></property>
      </bean>
</beans>

集合注入

public class CollData {

    private String[] arrayData;
    private List<String> listData;
    private Set<String> setData;
    private Map<String, String> mapData;
    private Properties propsData;

    //getters、setters、toString
}

public class TestColl {
    @org.junit.Test
    public void test() throws Exception {
        String xmlPath = "org/e/xml/DI_collection/beans.xml";

        ApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
        CollData data = (CollData) context.getBean("collDataId");
        System.out.println(data);
    }
}

<beans
    <!--
            集合的注入都是给<property>添加子标签
                数组:<array>
                List:<list>
                Set:<set>
                Map:<map> ,map存放k/v 键值对,使用<entry>描述
                Properties:<props>  <prop key=""></prop>  

            普通数据:<value>
            引用数据:<ref>
        -->
    <bean id="collDataId" class="org.e.xml.DI_collection.CollData" >
        <property name="arrayData">
            <array>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </array>
        </property>

        <property name="listData">
            <list>
                <value>Tom</value>
                <value>Alice</value>
                <value>Adam</value>
            </list>
        </property>

        <property name="setData">
            <set>
                <value>I</value>
                <value>Love</value>
                <value>You</value>
            </set>
        </property>

        <property name="mapData">
            <map>
                <entry key="Jack" value="杰克"></entry>
                <entry>
                    <key><value>rose</value></key>
                    <value>露丝</value>
                </entry>
            </map>
        </property>

        <property name="propsData">
            <props>
                <prop key="高富帅">嫐</prop>
                <prop key="白富美">嬲</prop>
                <prop key="男屌丝">挊</prop>
            </props>
        </property>
    </bean>
</beans>

装配Bean——基于注解

  • 注解:就是一个类,使用@注解名称
  • 开发中:使用注解 取代 xml配置文件。

    1. @Component取代<bean class="">
        @Component("id") 取代 <bean id="" class="">
    2.web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">
        @Repository :dao层
        @Service:service层
        @Controller:web层
    3.依赖注入,给私有字段设置,也可以给setter方法设置
        普通值:@Value("")
        引用值:
            方式1:按照【类型】注入
                @Autowired
            方式2:按照【名称】注入1
                @Autowired
                @Qualifier("名称")
            方式3:按照【名称】注入2
                @Resource("名称")
    4.生命周期
        初始化:@PostConstruct
        销毁:@PreDestroy
    5.作用域
        @Scope("prototype") 多例
    
  • 注解使用前提,添加命名空间,让spring扫描含有注解类

IOC

public interface UserService {
    public void addUser();
}

@Component("userServiceId")
public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("g_annotation.a_ioc add user");
    }
}

public class TestAnnoIoC {

    @Test
    public void test(){
        String xmlPath = "org/h/annotation/IOC/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService) applicationContext.getBean("userServiceId");
        userService.addUser();
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
    <!-- 组件扫描,扫描含有注解的类 -->
    <context:component-scan base-package="org.h.annotation.IOC"></context:component-scan>
</beans>

DI

public interface StudentDao {
    public void save();
}

@Repository("studentDaoId")
public class StudentDaoImpl implements StudentDao {
    @Override
    public void save() {
        System.out.println("好好学习,天天向上!");
    }
}

public interface StudentService {
    public void study();
}

@Service()
public class StudentServiceImpl implements StudentService {
    @Autowired
    @Qualifier("studentDaoId")
    private StudentDao dao;

    @Override
    public void study() {
        dao.save();
    }
}

@Controller("studentActionId")
public class StudentAction {
    @Autowired
    private StudentService service;

    public void execute(){
        service.study();
    }
}

public class TestAnnoWeb {

    @Test
    public void test(){
        String xmlPath = "org/h/annotation/web/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        StudentAction action = (StudentAction) applicationContext.getBean("studentActionId");
        action.execute();
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
    <!-- 组件扫描,扫描含有注解的类 -->
    <context:component-scan base-package="org.h.annotation.IOC"></context:component-scan>
</beans>

生命周期和作用域

public interface UserService {
    public void addUser();
}

@Service("userServiceId")
//@Scope("prototype")
public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("d_scope add user");
    }

    @PostConstruct
    public void myInit(){
        System.out.println("初始化");
    }
    @PreDestroy
    public void myDestroy(){
        System.out.println("销毁");
    }
}

public class TestOther {

    @Test
    public void test(){
        String xmlPath = "org/h/annotation/other/beans.xml";
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = applicationContext.getBean("userServiceId" ,UserService.class);
        UserService userService2 = applicationContext.getBean("userServiceId" ,UserService.class);

        System.out.println(userService);
        System.out.println(userService2);

        applicationContext.close();
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
    <!-- 组件扫描,扫描含有注解的类 -->
    <context:component-scan base-package="org.h.annotation.IOC"></context:component-scan>
</beans>

猜你喜欢

转载自blog.csdn.net/litianxiang_kaola/article/details/79121561