Spring学习笔记-------->IOC

Spring学习笔记-------->IOC

IOC理论推导

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

public interface UserDao {
     void getUser();
}
public class UserDaoImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("普通获取用户数据");
    }
}
public class  UserDaoMySqlImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("需求1:通过MySql获取");
    }
}

public class UserDaoOracleImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("需求2:通过Oracle获取数据");
    }
}

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserDaoImpl();//每次需求的更改都要修改此处实现类
    public void getUser(){
         userDao.getUser();
    }
}
public class MyTest {

    public static void main(String[] args) {
        UserService  userService=new UserServiceImpl();
        userService.getUser();
    }
}

image-20210508110320066

在之前的业务中,用户的需求可能回影响我们原来的代码,我们需要根据用户需求去修改原代码,如果程序代码量非常大,修改一次成本代价十分昂贵。

将UserDao 用set进行动态实现的注入

   private UserDao userDao;

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

之前,程序都是主动创建对象,控制权在程序员手上;

使用了set注入后 程序不再具有主动性,而是变成了被动的接受对象

这种思想,从本质上解决了问题,程序员再也不用去管理对象的创建了 ,系统的耦合度大大降低,可以更加专注在业务的实现上,这就是IOC的原型

public class MyTest {
    public static void main(String[] args) {
        //用户实际接触业务层  Dao层不需要接触
        UserService  userService=new UserServiceImpl();
        //接口不能实现类的特有方法,需要强转
        ((UserServiceImpl)userService).setUserDao(new UserDaoMySqlImpl());
        userService.getUser();
    }
}

image-20210508110110539

img

第一个spring项目 helloworld

设置bean.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
        http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!--使用spring来创建对象  在spring中 这些都称为bean
    bean=对象   id等价于变量名  class相当于new的对象
    value相当于给对象属性赋值-->
    <bean id="hello" class="com.phq.pojo.Hello" >
        <property name="str" value="Spring"/>
    </bean>
</beans>
public class MyTest {

    public static void main(String[] args) {
        //获取Spring的上下文对象
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在Spring中管理,要使用直接去里面取就可以
        Hello hello=(Hello)context.getBean("hello");
        System.out.println(hello.toString());
    }
}

image-20210508133531403

IOC创建对象的方式

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

 public User() {
        System.out.println("User的无参构造");
    }
<bean id="user" class="com.phq.pojo.User">
    <property name="name" value="温存"></property>
</bean>

2.1:有参构造下标方式

    public User(String name) {
        this.name = name;
        System.out.println("有参构造");
    }

<bean id="user" class="com.phq.pojo.User">
<!--    <property name="name" value="温存"></property>-->
    <constructor-arg index="0" value="有参测试"/>
</bean>

image-20210508140934942

2.2通过类型(不建议使用)

<bean id="user" class="com.phq.pojo.User">
<!--    <property name="name" value="温存"></property>-->
    <constructor-arg type="java.lang.String" value="类型赋值" />
</bean>

2.3通过参数名设置

<bean id="user" class="com.phq.pojo.User">
<!--    <property name="name" value="温存"></property>-->
    <constructor-arg name="name" value="类型赋值" />
</bean>
Spring配置
  • alias 别名 可以通过别名获取对象
  • id bean的唯一标识符
  • class bean对象所对应的全限定名
  • name 也是别名 可以同时取多个别名 可以通过空格 逗号 分号等等分隔
  • import 一把用于团队开发 可以将多个配置文件合并为一个
依赖注入(Dependency Injection)
构造器注入

上面已经讲过

Set方式注入
  • Set
    • 依赖:bean对象的创建依赖于容器
    • 注入:bean对象的属性有容器来注入
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> cards;
    private Set<String> games;
    private String wife;
    private Properties info;
}
<?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.xsd">

<bean id="student" class="com.phq.pojo.Student">
<!--    第一种:普通值注入-->
    <property name="name" value="温存"/>
<!--    第二种:Bean注入 ref-->
    <property name="address" ref="address"/>
<!--  数组注入-->
    <property name="books">
        <array>
            <value>红楼梦</value>
            <value>西游记</value>
            <value>水浒传</value>
        </array>
    </property>
<!--    List注入-->
    <property name="hobbys">
        <list>
            <value>吃饭</value>
            <value>睡觉</value>
        </list>
    </property>
<!--    Map注入-->
<property name="cards">
    <map>
        <entry key="身份证" value="1008611"/>
        <entry key="银行卡" value="1000000"/>
    </map>
</property>
    <!--    Set注入-->
    <property name="games">
        <set>
            <value>球球大作战</value>
            <value>奇迹暖暖</value>
        </set>
    </property>
<!--null-->
<property name="wife">
    <null></null>
</property>
<!--    properties-->
    <property name="info">
        <props>
            <prop key="学号"> 201720180000</prop>
            <prop key="性别"></prop>
            <prop key="姓名">法外狂徒张三</prop>
        </props>
    </property>
</bean>
    <bean id="address" class="com.phq.pojo.Address" >
        <property name="location" value="火星"/>
    </bean>
</beans>
Student{name='温存', address=Address{location='火星'}, books=[红楼梦, 西游记, 水浒传], hobbys=[吃饭, 睡觉], cards={身份证=1008611, 银行卡=1000000}, games=[球球大作战, 奇迹暖暖], wife='null', info={学号=201720180000, 性别=男, 姓名=法外狂徒张三}}

拓展方式注入
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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean name="john-modern"
        class="com.example.Person"
        p:name="John Doe"
        p:spouse-ref="jane"/>
</beans>
c命名空间 通过构造器注入
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">  
    <!-- c-namespace declaration -->
    <bean id="thingOne" class="x.y.ThingOne" c:thingTwo-ref="thingTwo" c:thingThree-ref="thingThree" c:email="[emailprotected]"/>

</beans>
Bean的作用域
ScopeDescription
singleton(默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。
prototype将单个 bean 定义的作用域限定为任意数量的对象实例。
request将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext中有效。
session将单个 bean 定义的范围限定为 HTTP Session的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
application将单个 bean 定义的范围限定为ServletContext的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
websocket将单个 bean 定义的范围限定为WebSocket的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。

单例模式: (Spring默认机制)

原型模式:每次从容器中get都会产生一个新的对象

其余的只能在WEB开发中使用到

bean的自动装配
  • spring会在上下文中自动寻找 并自动给bean装配属性
    • 在xml中显式的配置
    • 在java中显式的配置
    • 隐式的自动装配bean(重要)
环境搭建

一人一猫一狗

public class People {
    private String name;
    private Dog dog;
    private Cat cat;
    }
   <bean id="cat" class="com.phq.dao.Cat"/>
    <bean id="dog" class="com.phq.dao.Dog"/>
    <bean id="people" class="com.phq.dao.People" autowire="byName">
        <property name="name" value="温存"/>
    </bean>
  • byName 会自动到容器上下文中查找 和自己对象set方法后面的值对应的bean 的id

​ 使用时需要保证所有的bean的id唯一 并且这个bean需要和自动注入的属性的set方法一致

  • byType 会自动到容器上下文中查找 和自己对象属性类型相同的bean

​ 使用时需要保证所有的bean的class唯一 并且这个bean需要和自动注入的属性一致

使用注解进行自动装配

jdk1.5支持的注解 spring2.5就支持注解了

大多时候会使用注解进行开发

  • 导入约束
  • 配置注解的支持
<?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">
    <context:annotation-config/>
</beans>
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

@Autowired

直接在属性上使用即可, 也可以在set方法上使用,

@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。

如果自动装配环境比较复杂,可以加上@Qualifier,则可以根据byName的方式自动装配

@Resource
private Cat cat;
@Resource
private Dog dog;

@Resource 如有指定的name属性,先按该属性进行byName方式查找装配;

其次再进行默认的byName方式进行装配;

如果以上都不成功,则按byType的方式自动装配。

都不成功,则报异常。

Recource 和Autowired的区别:

1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

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

3、@Resource默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名(byName)进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型(byType)进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

使用注解开发

在spring4 以后 要使用注解开发必须要保证aop的包导入了,使用注解需要导入context约束 添加注解的支持

1:bean

@Component注解 说明类被spring管理

2:属性如何注入

//等价于<bean id="user" class="com.phq.pojo.User"
@Component
public class User {
    @Value("温存")
  //等价于<property name="naem" value="温存"/>
    public String name;
//@Value("温存")    也可以放在set方法上
    public void setName(String name) {
        this.name = name;
    }
}

3:衍生的注解

@Component的衍生注解 在web开发中 会按照mvc三层架构分层

  • dao层: @Repository
  • service层 @service
  • controller层 @Controller

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

4:自动装配

5:作用域

@Scope9("singleton")

6:小结

xml与注解:

  • 注解最万能 适用于任何场合 维护方便
  • 注解 不是自己的类用不了 维护相对复杂

最佳处理方法

  • xml用来管理bean
  • 注解完成属性的注入
  • 使用时必须开启注解支持
 <context:component-scan base-package="com.phq"/>
    <context:annotation-config/>
使用java的方式配置spring

完全不使用spring 的xml配置 全权交给java做

javaConfig是spring的一个子项目, 在spring4以后 成为一个新功能

pojo:

public class User {
    public String name;

    public String getName() {
        return name;
    }
    @Value("测试")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

@Configuration
@ComponentScan("com.phq.pojo")
@Import(MyConfig2.class)  //引入其他配置文件同时使用
public class MyConfig {

    //注册一个bean  相当于xml添加bean标签
    //这个方法的名字就相当于bean中的id属性
    //返回值就相当于bean标签的class属性
    @Bean
    public User User(){
        return new User();
    }
}
public class MyConfig2 {

    //注册一个bean  相当于xml添加bean标签
    //这个方法的名字就相当于bean中的id属性
    //返回值就相当于bean标签的class属性
    @Bean
    public User User2(){
        return new User();
    }
}

测试导入MyConfig 使用MyConfig2中的方法名:

   @Test
    public void test1(){
        //如果完全使用配置类去做  就只能通过AnnotationConfig获取容器 通过配置类的class对象加载
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("User2", User.class);
        System.out.println(user.getName());
    }
}

image-20210509105036651

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

phqovo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值