IOC

IOC理论推导

最初:

  1. dao层
package dao;

//接口
public interface UserDao {
    //获取普通用户信息
    void getUser();
}
///////////////////////////
package dao;
//实现
public class UserDaoImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("普通用户实现");
    }
}
///////////////////////////////
package dao;

public class UserDaoMysqlImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("mysql用户实现");
    }
}
/////////////////////////////
package dao;

public class UserDaoOracleImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("Oracle用户实现");
    }
}
  1. service层
package service;
//接口
public interface UserService {
    void getUser();
}
///////////////
package service;

//实现
import dao.UserDao;
public class UserServiceImpl implements UserService{
   // private UserDao userDao = new UserDaoImpl();
   //private UserDao userDao = new UserDaoMysqlImpl();
   private UserDao userDao;
        //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
    userDao.getUser();
    }
}
  1. servlet层

  1. 测试
import dao.UserDaoMysqlImpl;
import service.UserServiceImpl;

public class MyTest {
    public static void main(String[] args) {

        //用户调的是业务层,不会去掉dao层,用户接触不到dao层
        UserServiceImpl userService = new UserServiceImpl();

        //这里调用set方法,动态修改了,无需写死
        userService.setUserDao(new UserDaoMysqlImpl());
        userService.getUser();

    }

}
  • 之前程序是主动创建对象,要由自己去创建,控制权在自己手上
  • 使用了set注入后,程序不再有主动性,而是变成了被动的接收对象!!

这种实现从本质上解决了问题,我们可以不用再去管理程序的创建了。系统的耦合性大大降低IOC原型!!

4. ICO创建对象方式

  1. 默认使用无参构造创建对象

    <bean id="serviceImpl" class="service.UserServiceImpl">
        <property name="userDao" ref="mysqlImpl"/>
       </bean>
    
  2. 有参构造创建对象

    1. 下标赋值

      <bean id="hello" class="pojo.Hello">
      <!--<property name="name" value="spring"/>-->
          <constructor-arg index="0" value="狂神"/>
      </bean>
      
    2. 通过类型创建

      <bean id="hello" class="pojo.Hello">
      
          <!--有参,类型赋值 不建议使用,有两个String参数,没有办法-->
          <constructor-arg type="java.lang.String" value="狂神说Java"/>
      </bean>
      
    3. 直接通过参数名来设置

      <bean id="hello" class="pojo.Hello">
              <constructor-arg name="name" value="开源"/>
          </bean>
      

    在配置文件加载的时候,容器中管理的队像就已经初始化了!!

5,Spring配置

5.1,别名

<!--    别名,如果添加了别名,我们也可以通过别名获取到这个对象-->
    <alias name="hello" alias="sadadsa"/>

5.2,Bean的配置

<!--
id: bean的唯一标识符,相当于我们的对象名
class: bean 对象所对应的全限定名:包名+类名
name : 也是别名,而且name可以同时取多个,别名
-->
    <bean id="hello" class="pojo.Hello" name="hello2,h32">
        <constructor-arg name="name" value="laoqing"/>
    </bean>

5.3, import

这个import,一般用于团队开发,可以将多个配置文件 ,导入合并为一个

<import resource="beans.xml"/>
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>

使用的时候直接使用总的配置就可以了

6, 依赖注入

6.1, 构造器注入

6.2,Set方式注入

  • 依赖注入:Set注入!
    • 依赖:bean对象的创建依赖与容器
    • 注入:bean对象中的属性,由容器注入

【环境搭建】

  1. 复杂类型

    public class Address {
        private  String Address;
    
        public String getAddress() {
            return Address;
        }
    
        public void setAddress(String address) {
            Address = address;
        }
    }
    
  2. 真实测试类型

    public class Student {
    private String name;
    private Address address;
    private String[] book;
    private List<String> hobby;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;}
    
  3. beans.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="student" class="pojo.Student">
            <!--第一种:普通值注入,value-->
            <property name="name" value="狂神"/>
        </bean>
    </beans>
    
  4. 测试类

    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            Student student = (Student) context.getBean("student");
            System.out.println(student);
        }
    }
    

完善注入信息

<?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">
    <bean id="address" class="pojo.Address">
        <property name="address" value="河北"/>
    </bean>
    <bean id="student" class="pojo.Student">
        <!--第一种:普通值注入,value-->
        <property name="name" value="狂神"/>
        <!--第二种:Bean注入,ref-->
        <property name="address" ref="address"/>
        <!--第三种:数组注入,ref-->
        <property name="book">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>水浒传</value>
                <value>三国演义</value>
            </array>
        </property>
        <!--List-->
        <property name="hobby">
            <list>
                <value>听歌</value>
                <value>敲代码</value>
                <value>看电影</value>
                <value>写作</value>
            </list>
        </property>
        <!--Map-->
        <property name="card">
            <map>
                <entry key="身份" value="学生"/>
                <entry key="银行卡" value="623059150902486754"/>
            </map>
        </property>
        <!--Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>DNF</value>
            </set>
        </property>
        <!--null-->
        <property name="wife">
          <null/>
        </property>
        <!--Properties-->
        <property name="info">
            <props>
                <prop key="学号">2022</prop>
                <prop key="年龄">18</prop>
                <prop key="性别"></prop>
            </props>
        </property>
    </bean>
</beans>

结果:

/*
* Student{name='狂神',
*  address=Address{Address='河北'},
*  book=[红楼梦, 西游记, 水浒传, 三国演义],
* hobby=[听歌, 敲代码, 看电影, 写作],
* card={身份=学生, 银行卡=623059150902486754},
* games=[LOL, DNF],
* wife='null',
* info={学号=2022, 性别=男, 年龄=18}}
* */

6.3,其他方式拓展方式注入

我们可以使用P命名空间和C命名空间进行注入

官方解释:

  1. p命名:基于无参构造

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean name="classic" class="com.example.ExampleBean">
            <property name="email" value="someone@somewhere.com"/>
        </bean>
    
        <bean name="p-namespace" class="com.example.ExampleBean"
            p:email="someone@somewhere.com"/>
    </beans>
    
  2. C命名:基于有参构造

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean name="john-classic" class="com.example.Person">
            <property name="name" value="John Doe"/>
            <property name="spouse" ref="jane"/>
        </bean>
    
        <bean name="john-modern"
            class="com.example.Person"
            p:name="John Doe"
            p:spouse-ref="jane"/>
    
        <bean name="jane" class="com.example.Person">
            <property name="name" value="Jane Doe"/>
        </bean>
    </beans>
    

测试:

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student",Student.class);
        System.out.println(student);

注意:P命名和c命名空间不能直接使用,需要导入xml约束

6.4,Bean的作用域

  1. 单例模式(Spring默认的机制)

    <bean id="address" class="pojo.Address" scope="singleton">
    
  2. 原型模式:每次从容器中gat时,都会产生一个新对象

    <bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
    
  3. 其他的 request, session, application,这些只能在web开发中使用到!

7, Bean的自动装配

  • 自动装配是Spring满足bean依赖一种方式!
  • Spring会在上下文中自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式

  1. 在xml中显示的配置
  2. 在Java中显示的配置
  3. 隐式的自动装配bean【重要】

7.1,测试

环境搭建:一个人有两个宠物

7.1,ByName自动装配

<bean id="people" class="pojo.People" autowire="byName">
        <property name="name" value="张三"/>
<!--        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>-->
    </bean>

7.2, ByType自动装配

<bean id="dog" class="pojo.Dog"/>
<bean id="cat" class="pojo.Cat"/>
    <!--
    byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id
    -->
    <bean id="people" class="pojo.People" autowire="byType">
        <property name="name" value="张三"/>
<!--        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>-->
    </bean>

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • byType的时候,需要保证所有bean的clas唯一,并且这个bean需要和自动注入的属性的类型一致!

7.4,使用注解实现自动装配

使用注解须知:

  1. 导入约束,context约束

  2. 配置注解支持: context:annotation-config/

    <?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
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:annotation-config/>
    
    </beans>
    

@Autowired

直接在属性上使用即可!也可以在set方式上使用!

使用Autowired我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC (Spring)容器中存在,且符合名字byName

科普:

@Nullable 字段标记了这个注解,说明这个字段可以为null;

public @interface Autowired {
    boolean required() default true;
}

//如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value="xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入!

public class People {
@Autowired
Qualifier(value="cat111")
private cat cat;
@Autowired
Qualifier(value="dog222")
private Dog dog;
private string name;
}

@Resource注解

public class People {
@Resource(name = "cat2")
private cat cat;
@Resource
private Dog dog;
}

小结:

@Resource和@ Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired默认按类型(ByType)查找,如果存在多个对象再按名字(ByName)查找。
  • @Resource默认按名称查找,如果找不到再按类型查找。
  • 执行顺序不同:@Autowired通过byType的方式实现。

8,使用注解开发

在Spring4之后,要使用注解开发,必须要保证aop的包导入了

使用注解需要导入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
        https://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context 
https://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
</beans>
  1. bean

  2. 属性如何注入

    //等价与等价于<bean id="user" class="com.kuang.pojo.User"/
    //@Component 组件
    @Component
    public class User {
      //相当于<property name= "name" value="huangshen" />
        @Value("qing")
        public String name;
    }
    //还可以加在set方法上
    @Value("qing")
        public void setName(String name) {
            this.name = name;
        }
    
  3. 衍生的注解

    @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!

    • dao【@Repository
    • service【@Service
    • controller 【@Controller

    这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean

  4. 自动装配

    @Autowired :自动装配通过类型。名字
    	如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")@Nullable字段标记了这个注解,说明这个字段可以为null;
    @Resource:自动装配通过名字。类型。
    
  5. 作用域

    @component
    @scope("prototype")原型模式/单例模式
    public class user{
    public string name;
    //相当于<property name="name " value="kuangshen" />
    @value("kuangshen2")
    public void setName(string name) i
    this.name = name;
    }
    }
    
  6. 小结

    xml 与注解

    • 注解不是自己类使用不了,维护相对复杂!
    • xml更加万能,适用于任何场合!维护简单方便。

    xml与注解最佳实践:

    • xml 用来管理bean;
    • 注解只负责完成属性的注入;
    • 在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
posted @   明眸清澈  阅读(142)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示