Spring入门之再再再次理解IOC

再再再再次理解IOC

控制反转,对一个对象控制权的反转。再使用spring之后,会把对象的创建,初始化和销毁等操作交给spring容器来管理,也就是在项目启动的时候,bean就会增加注册到spring容器当中去,而其他Bean需要使用这个Bean的话,就不需要自己去new,而是直接去Spring容器里拿

“控制反转其实就是控制权的反转,本来对象的控制权可能在另一个对象那边,而spring的出现让对象的控制权留在了容器当中”

并开始简单尝试:
首先创建一个新的Maven项目:
在这里插入图片描述
next
在这里插入图片描述
finish
先在pom.xml这边导入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.3</version>
    </dependency>
</dependencies>

并创建spring-config : applicationContext
在这里插入图片描述
在这个applicationContext.xml下面就可以配置所有注册到spring中的Bean文件了

首先在java下面创建包,在包里创建一个User类

package org.wzw.ioc.model;

public class User {
    private  String username;
    private  String address;
    private Integer userid;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Integer getUserid() {
        return userid;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }
}

并创建一个Main方法用来调用User
正常是这样的

package org.wzw.ioc.model;

public class Main {
    public static void main(String[] args) {
        User user = new User();
        System.out.println("user"+user);
    }
}

对应的输出:
在这里插入图片描述
进行修改:
首先在applicationContext.xml文件这边创建一个bean

<bean class="org.wzw.ioc.model.User" id="user"> </bean>

这里有个细节,class属性是作为需要注册的bean的全路径,而id则表示bean的唯一标记,也可以把name作为bean的标记,但一般情况下,id和name是一样的。

而且bean其实是用了java里的反射,通过class这里可以看到

package org.wzw.ioc;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.wzw.ioc.model.User;

public class Main {
    public static void main(String[] args) {
       /* User user = new User();
        System.out.println("user"+user);*/
        //针对bean来创建实例,是利用了反射
        //当这行代码执行的时候,user就会被初始化,并且放在spring容器当中
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //就和反射一样 被初始化了 就可以进行调用了
        User user = (User) context.getBean("user");
        //感觉上面这句代码的意思就是 User user=new User();
        User user1 = context.getBean("user", User.class);
        //另一种方法
        User user2 = context.getBean(User.class);
        //这个方法是存在缺陷的
        System.out.println("user = " + user);
        System.out.println("user1 = " + user1);
        System.out.println("user2 = " + user2);
    }
}

而针对其中这些个方法,还是有不同的getBean的方法的,并且对应直接.class的方法,其实是不太好的

再者就是关于属性的注入
1.构造方法注入:
首先看到是需要在User这边创建一个有参的构造方法

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

在这里插入图片描述
在这里插入图片描述
然后会看到,首先是因为存在了有参的构造函数,上一个会报错,提示你需要输入构造函数的参数,其次关于输入构造函数,有index(从0 开始)和name(对应的name)

<bean class="org.wzw.ioc.model.User" id="user">
<constructor-arg name="address" value="11"/>
 <constructor-arg name="userid" value="1"/>
    <constructor-arg name="username" value="231"/>
</bean>

并且可以Override toString方法用来输出

@Override
public String toString() {
    return "User{" +
            "username='" + username + '\'' +
            ", address='" + address + '\'' +
            ", userid=" + userid +
            '}';
}

然后调用就会发现
在这里插入图片描述
set方法注入

<bean class="org.wzw.ioc.model.User" id="user2">
    <property name="username" value="11111"/>
</bean>

这里的id是user2
当然这样就需要在User里存在一个无参的构造函数
并在Main方法上

User user2 = (User) context.getBean("user2");
System.out.println("user2 = " + user2);

这样子输出,按照那个toString方法,没有设置 address和userid,所以他们都是默认null
在这里插入图片描述
并且可以通过一个小方法来验证,这个property就是调用了对应的set方法
可以在setUsername这边随便写一个

public void setUsername(String username) {
    System.out.println("应该是用了这个方法吧");
    this.username = username;
}

再运行一次
在这里插入图片描述

有个小细节:set中的属性名,都不是你在bean中定义的属性名,而是“通过java内省机制分析出来的属性名,也就是从get/set方法中分析出来的属性名"

p名称空间注入
本质上也是调用set/get方法

<bean class="org.wzw.ioc.model.User" id="user3" p:username="www"  p:userid="11"/>

同理 创建User3

User user3 = (User) context.getBean("user3");
System.out.println("user3= " + user3);

运行
在这里插入图片描述
这个也证实了,调用的是set方法

外部Bean的注入
主要是静态工厂注入和实例工厂注入

复杂属性注入
1.对象注入 (就是之前的方法)
首先随便创建一个对象,并在User中把这个对象导入

package org.wzw.ioc.model;

public class Cat {
    private String catName;
    private int catId;

    @Override
    public String toString() {
        return "Cat{" +
                "catName='" + catName + '\'' +
                ", catId=" + catId +
                '}';
    }

    public String getCatName() {
        return catName;
    }

    public void setCatName(String catName) {
        this.catName = catName;
    }

    public int getCatId() {
        return catId;
    }

    public void setCatId(int catId) {
        this.catId = catId;
    }
}

并在User中加入 Cat对象,以及Get/Set方法和重写toString方法

<bean class="org.wzw.ioc.model.User" id="user4">
   <property name="username" value="name"/>
    <property name="address" value="value"/>
    <property name="userid" value="8"/>
    <property name="cat" ref="cat"/>
</bean>

<bean class="org.wzw.ioc.model.Cat" id="cat">
    <property name="catId" value="101"/>
    <property name="catName" value="mayo"/>
</bean>

运行一下
在这里插入图片描述

但很有意思的是,我并没有在User的构造函数这边写上Cat,结果效果是一样的
数组的注入
在User这边创建一个int[]类型的数组
并加入Get/Set方法 和修改toString方法

@Override
public String toString() {
    return "User{" +
            "username='" + username + '\'' +
            ", address='" + address + '\'' +
            ", userid=" + userid +
            ", cat=" + cat +
            ", goodNums=" + Arrays.toString(goodNums) +
            '}';
}

然后是xm文件

<bean class="org.wzw.ioc.model.User" id="user4">
   <property name="username" value="name"/>
    <property name="address" value="value"/>
    <property name="userid" value="8"/>
    <property name="cat" ref="cat"/>
    <property name="goodNums">
        <array>
            <value>1</value>
            <value>2</value>
        </array>
    </property>
</bean>

其中,array可以用list节点来替代 ,并且在list和array中,是可以加入bean对象,也就是在里面也还能再加东西(当然,前提是同一种数据类型)
Map注入

private Map<String,Object> details;

并加入Get/Set方法 和修改toString方法
xml文件中加入

<property name="details">
    <map>
        <entry key="衣服" value="扣扣扣"></entry>
        <entry key="身份证" value="12312"/>
    </map>
</property>

运行
在这里插入图片描述

Properties(配置)注入

private Properties info;

并加入Get/Set方法 和修改toString方法
xml文件中加入

<property name="info">
    <props>
        <prop key="age">21</prop>
        <prop key="性别"></prop>
    </props>
</property>

运行
在这里插入图片描述
java配置
有三种配置方法
1.java配置(适合spring-boot)
创建一个SayHello.java

package org.wzw.ioc.javaconfig;

public class SayHello {
    public String sayHello(String name){
        return  "hello"+name;
    }
}

使用java配置的话,就用一个配置类去代替之前的.xml

package org.wzw.ioc.javaconfig;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//作用类似于applicationContext.xml
@Configuration
//加这个注解说明他是个配置类
public class JavaConfig {
    //就是把原本放在xml文件里的东西放到这里来
    @Bean
    SayHello sayHello(){
        return new SayHello();
    }
    //定义方法,方法返回对象 这个返回的对象就是new,并且会把这个返回的对象注入到Spring容器当中
}

在main函数里写入

AnnotationConfigApplicationContext acx = new AnnotationConfigApplicationContext(JavaConfig.class);
SayHello sayHello = (SayHello) acx.getBean("sayHello");
System.out.println(sayHello.sayHello("wwwww"));

运行
在这里插入图片描述

小细节就是,这里的bean是可以改名字的,改成@Bean(“asdas”)都行,默认是方法名,并且由于getBean的各种各样,也有好几种写法

2.自动扫描注入
他可以是java配置的,也可以是xml配置的,使用频率很高
这里就涉及到了注解:这个真的老生常谈了

  1. @Component 在其他组件上添加注解
  2. @Repository 在Dao层添加注解
  3. @Service 在Service层添加注解
  4. @Controller 在Controller层添加注解

他们都是由Componeent 做出来的,并且功能也是一样, 但变成三个的原因就是为了在不同类上添加的时候方便一点

package org.wzw.ioc.Service;

import org.springframework.stereotype.Service;
import org.wzw.ioc.model.User;

import java.util.ArrayList;
import java.util.List;
@Service
public class UserService {
    public List<String> getAllUsers(){
        List<String> users=new ArrayList<>();
        for(int i=0;i<10;i++){
            users.add(i, "a");
        }
        return users;
    }

}

2.1java配置

//作用类似于applicationContext.xml
@Configuration
@ComponentScan(basePackages = "org.wzw.ioc.Service")
//加这个注解就可以进行扫描对应包下面的实体类了,默认是扫描配置类,也就是JavaConfig这个类下面的包以及所在包的子包下面的类
//加这个注解说明他是个配置类
public class JavaConfig {
    //就是把原本放在xml文件里的东西放到这里来
    }
    //定义方法,方法返回对象 这个返回的对象就是new,并且会把这个返回的对象注入到Spring容器当中
}

main方法

AnnotationConfigApplicationContext acx = new AnnotationConfigApplicationContext(JavaConfig.class);
UserService getAllUsers = acx.getBean("getAllUsers", UserService.class);
System.out.println(getAllUsers.getAllUsers());

运行一下
在这里插入图片描述

这里的名字,那就是直接根据Serviece

2.1xml配置
在xml文件里
<context:component-scan base-package=“org.wzw.ioc.Service”/>

修改main方法

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = context.getBean(UserService.class);
System.out.println(bean.getAllUsers());

这里可是用的是ClassPathXmlApplicationContext

对象注入问题
也有三种方式

  1. @Autowired
  2. @Resources
  3. @Injected

总的来说就是 Injected不太使用,而Autowired则是根据类型来查找的,所以有个潜在的条件就是类型只可以有一个对象(一般是最常见的),而Resources则是根据名称查找的,默认情况下,定义的变量名就是查找的名称,但也是可以再注解中手动指定的。所以,如果一个类中存在多个实例的时候,一般是使用Resources,而如果一定要用Autowired的话,是需要@Qualifier这个注解配合使用的,这样才能可以通过变量名查找到变量

package org.wzw.ioc.Dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public String userDao(){
        return "helloDao";
    }
    
}

然后注入一下

@Autowired
UserDao userDao;

public String HelloDao(){
   return userDao.userDao();
}

对应的,xml就需要改一下,不然扫描不到

<context:component-scan base-package="org.wzw.ioc"/>

条件注解
依次创建
在这里插入图片描述
LinuxCondition:

package org.wzw.ioc.cmd;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

//这个需要继承一个方法
public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //就是返回这个数据是否是win
        return  context.getEnvironment().getProperty("os.name").toLowerCase().contains("linux");

    }
}

LinuxShowCmd:

package org.wzw.ioc.cmd;

public class LinuxShowCmd implements ShowCmd{
    @Override
    public String ShowCmd() {
        return "ls";
    }
}

ShowCmd

package org.wzw.ioc.cmd;

public interface ShowCmd {
    //这个接口实现一个方法
    public String ShowCmd();
}

WindowsCondition:

package org.wzw.ioc.cmd;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").toLowerCase().contains("win");
    }
}

WindowsShowCmd:

package org.wzw.ioc.cmd;

public class WindowsShowCmd implements ShowCmd{
    @Override
    public String ShowCmd() {
        return "dir";
    }
}

然后是JavaConfig

public class JavaConfig {
    //就是把原本放在xml文件里的东西放到这里来

    @Bean("www")
    @Conditional(WindowCondition.class)
    ShowCmd winCmd(){
        return new WindowsShowCmd();
    }
    @Bean("www")
    @Conditional(LinuxCondition.class)
    ShowCmd linuxCmd(){
        return  new LinuxShowCmd();
    }
}

并且在Main函数这边测试一下:

a

运行,因为现在是在windows下面的:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值