Spring配置bean的管理

1、Spring配置

别名

alias设置别名,为bean设置别名,可以设置多个别名

<!--设置别名:在获取Bean的时候可以使用别名获取-->
<alias name="userT" alias="userNew"/>

Bean的配置

<!--bean就是java对象,由Spring创建和管理-->
<?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的管理-->

    <!--beanFactory、applicationContext 接口-->
    <bean id="orderService" class="com.k2.bean的管理.实现接口.service.impl.OrderServiceImpl"/>

<!--bean的配置-->
    <!--使用id属性定义bean1、构造方法实例化-->
    <bean id="bean1" class="com.k2.bean的管理.bean的配置.beans.Bean1"/>
    <!--使用name属性定义bean2-->
    <bean id="bean2" class="com.k2.bean的管理.bean的配置.beans.Bean2"/>
    <!--
       id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
       如果配置id,又配置了name,那么name是别名
       name可以设置多个别名,可以用逗号,分号,空格隔开
       如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;
 
    class是bean的全限定名=包名+类名
    -->
    <bean id="hello" name="hello2 h2,h3;h4" class="com.k2.pojo.Hello">
       <property name="name" value="Spring"/>
    </bean>

    <!-- 静态工厂实例化   就是直接可以通过静态方法来实例化一个对象 -->
    <bean id="beanStatic" class="com.k2.bean的管理.bean的配置.static_factory.MyBeanStaticFactory" factory-method="createBean"></bean>

    <!-- 实例工厂实例化   就是先创建类对象,如何通过对象来调用创建实例对象的方法 -->
    <!-- 配置工厂 -->
    <bean id="myBeanFacFactory" class="com.k2.bean的管理.bean的配置.fac_factory.MyBeanFacFactory"></bean>
    <!-- 使用factory-bean属性指向配置的实例工厂,       相当于new MyBeanFacFactory,然后调用方法
        使用factory-method属性确定使用工厂中哪个方法
        先获取工厂对象(myBeanFacFactory),再获取工厂方法(createBean)
    -->
    <bean id="beanFac" factory-bean="myBeanFacFactory" factory-method="createBean"></bean>

    <!--看似没有创建MyBeanFactory对象,实则实现接口,已经创建对象-->
    <bean id="bean" class="com.k2.bean的管理.bean的配置.fac_factory.MyBeanFactory"/>

    <!-- Bean生命周期 -->
    <!-- scope="singleton" 这个值默认,在默认情况下spring能够全程跟踪bean的生命周期 -->
    <bean id="life" class="com.k2.bean的管理.bean的生命周期.entity.Life" init-method="initMethod" destroy-method="destroyMethod"></bean>

</beans>	

import

用于团队和合作通过import来实现

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

<import resource="{path}/beans.xml"/>

2、依赖注入

概念

  • 依赖注入(Dependency Injection,DI)。
    • 依赖:bean对象的创建依赖于容器
    • 注入:bean对象中的所有属性,由容器来注入
构造方法注入:
    确定参数的:
        name属性: 通过参数的名字来确定参数
        type属性: 通过参数的类型来确定参数
        index属性:通过参数的下标来确定参数
    给属性赋值的:
        value属性:用来给基本数据类型赋值
        ref属性:  用来给引用数据类型赋值

属性setter方法注入:
    name的值准确的讲并不是属性名,而是set方法去掉set关键字后的名字

2.1、构造器注入

2.2、Set注入【重点】

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is

【环境搭建】

User实体类

public class User2 {

    private int id;
    private String userName;
    private String passWord;
}

public class User3 {
    /**
     * 依赖注入 值的注入 有属性、有set方法才可以动态赋值
     */

    private String name;

    private List<String> list;

    private Set<String> set;

    private String[] array;

    private Map map;
    // 配置类
    private Properties prop;

    private User2 user2;

    private String wife;	// Null注入
    
    public void setWife(String wife){
        this.wife = wife;
    }
    public String getWife(){
        return wife;
    }
    
    public void setUser2(User2 user2) {
        this.user2 = user2;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setArray(String[] array) {
        this.array = array;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public void setProp(Properties prop) {
        this.prop = prop;
    }

    @Override
    public String toString() {
        return "User3{" +
                "name='" + name + '\'' +
                ", list=" + list +
                ", set=" + set +
                ", array=" + Arrays.toString(array) +
                ", map=" + map +
                ", prop=" + prop +
                ", user2=" + user2 +
                '}';
    }
}

常量注入

<bean id="user3" class="com.k2.DI依赖注入.User3">
    <property name="name" value="卑微小焦"></property>
</bean>

Bean注入

<bean id="user2" class="com.k2.DI依赖注入.User2">
    <property name="id" value="2"></property>
    <property name="userName" value="李四"></property>
    <property name="passWord" value="1234"></property>
</bean>

<bean id="user3" class="com.k2.DI依赖注入.User3">	
	<property name="user2" ref="user2"></property>
</bean>

数组注入

<bean id="user3" class="com.k2.DI依赖注入.User3">
    <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
                <value>array3</value>
            </array>
        </property>
</bean>

List注入

<bean id="user3" class="com.k2.DI依赖注入.User3">
    <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
</bean>

Set注入

<bean id="user3" class="com.k2.DI依赖注入.User3">
    <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>
</bean>

Map注入

<bean id="user3" class="com.k2.DI依赖注入.User3">
    <property name="map">
            <map>
                <entry key="key1" value="value1"></entry>
                <entry key="key2" value="value2"></entry>
                <entry key="key3" value="value3"></entry>
            </map>
        </property>
</bean>

Properties注入

<bean id="user3" class="com.k2.DI依赖注入.User3">
    <property name="prop">
            <props>
                <prop key="username">小焦同学</prop>
                <prop key="password">123</prop>
                <prop key="email">jiao@126.com</prop>
            </props>
        </property>
</bean>

Null注入

<bean id="user3" class="com.k2.DI依赖注入.User3">
    <property name="wife"><null/></property>
</bean>

2.3、注入拓展

p命名和c命名注入

<!--使用p(properties)命名空间引入,属性依然要设置set方法-->
导入约束:xmlns:p="http://www.springframework.org/schema/p"
<bean id="kuangUser" class="com.k2.DI依赖注入.KuangUser" p:name="小焦" p:age="18"/>


<!--使用c(Constructor)命名空间引入,属性依然要设置set方法
	有参构造器加上,这里也能知道,c 就是所谓的构造器注入!
-->
导入约束:xmlns:c="http://www.springframework.org/schema/c"
<bean id="kuangUser2" class="com.k2.DI依赖注入.KuangUser" c:name="青椒" c:age="16"/>

在这里插入图片描述

2.4、bean的作用域

在这里插入图片描述

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

singleton:单例模式(默认)。Spring容器中只会存在一个共享的Bean实例,所有对Bean的请求,只要请求的id(name)与Bean的定义相匹配,会返回Bean的同一个实例,Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

<bean id="scope1" class="com.k2.bean的管理.bean的配置.scope.Scope" scope="singleton"/>

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

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

<bean id="scope2" class="com.k2.bean的管理.bean的配置.scope.Scope" scope="prototype"/>
    // prototype:原型模式,每次从容器中请求Bean时,都会产生一个新的实例

3、其余的request、session、application这些只能在web开发中使用

3、自动装配Bean

  • 自动装配是使用spring满足bean依赖的一种方法
  • spring会在应用上下文中为某个bean寻找其依赖的bean

Spring中bean三种装配机制:

  1. 在xml中显式配置
  2. 在java中显式配置
  3. 隐式的bean发现机制和自动装配

Spring的自动装配需要从两个角度来实现,或者说是两个操作:

  1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
  2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

推荐不使用自动装配xml配置 , 而使用注解 .

3.1、xml方式自动装配

实体类

public class User1 {

    private int id;
    private String userName;
    private String passWord;

    public User1(int id, String userName, String passWord) {
        this.id = id;
        this.userName = userName;
        this.passWord = passWord;
    }   
}


public class User2 {

    private int id;
    private User1 user1;

    public void setId(int id) {
        this.id = id;
    }

    public void setUser1(User1 user1) {
        this.user1 = user1;
    }
}

applicationContext.xml

ByName方式

<?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="user1" class="com.k2.bean的管理.bean的装配.自动装配.User1">
        <constructor-arg name="userName" value="焦焦"></constructor-arg>
    </bean>
    <!--属性setter方法注入-->
    <bean id="user2" class="com.k2.bean的管理.bean的装配.自动装配.User2" autowire="byName">
        <property name="id" value="2"></property>
        <!--<property name="user1" ref="user1"></property>-->
    </bean>
    
</beans>

结论:

当一个bean节点带有 autowire byName的属性时。

  1. 将查找其类中所有的set方法名,例如setUser1,获得将set去掉并且首字母小写的字符串,即user1。
  2. 去spring容器中寻找是否有此字符串名称id的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常。

byType方式

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。id="user1"可以省略不写

<?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="user1" class="com.k2.bean的管理.bean的装配.自动装配.User1">
        <constructor-arg name="userName" value="焦焦"></constructor-arg>
    </bean>
    
    <!--属性setter方法注入-->
    <bean id="user2" class="com.k2.bean的管理.bean的装配.自动装配.User2" autowire="byType">
        <property name="id" value="2"></property>
        <!--<property name="user1" ref="user1"></property>-->
    </bean>   
</beans>

结论:如果把id="user1"删掉不会报错,因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

3.2、使用注解

jdk1.5开始支持注解,spring2.5开始全面支持注解

注解可以写在属性上,也可以写在setter方法上

在spring配置文件中引入context文件头

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

// 开启属性注解支持
<context:annotation-config/>

1、@Autowired

  • @Autowired是按类型自动装配的,不支持id匹配。可以没有set方法
  • 需要导入 spring-aop的包!
byName:根据<bean>元素id属性的值自动装配
byType:根据<bean>元素的数据类型(Type)自动装配,如果一个Bean的数据类型,兼容另一个Bean中的数据类型,则自动装配

实体类

public class Cat{
    
}
public class Dog{
    
}

public class User {
   @Autowired
   private Cat cat;
   @Autowired
   private Dog dog;
   private String str;

   public Cat getCat() {
       return cat;
  }
   public Dog getDog() {
       return dog;
  }
   public String getStr() {
       return str;
  }
}

applicationContext.xml

<context:annotation-config/>

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
1.1、@Qualifier
  • @Autowired默认是根据类型自动装配的,加上@Qualifer则可以根据byName的方式自动装配
  • @Qualifier不能单独使用

applicationContext.xml

<context:annotation-config/>

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>

在属性上添加Qualifier注解

@Autowired
private Cat cat;
// @Autowired默认根据类型自动装配,如果有多个实现类,需要配合@Qualifier注解使用,根据bean id(byName)自动装配
@Autowired
@Qualifier(value = "dog1")
private Dog dog;
1.2、required

@Autowired(required = false)说明:对象可以为null;可以不用配置bean

@Autowired(required = true)默认为true说明:对象必须存在,不能为null;配置bean

//如果允许对象为null,设置required = false,默认为true
@Autowired(required = false)
private Cat cat;

2、@Resource

  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
  • 其次再进行默认的byName方式进行装配;
  • 如果以上都不成功,则按byType的方式自动装配。
  • 都不成功,则报异常。

实体类

public class User {
   //如果允许对象为null,设置required = false,默认为true
   @Resource(name = "cat2")
   private Cat cat;
    
   @Resource
   private Dog dog;
   private String str;
}

applicationContext.xml

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User"/>

3、小结:

@Autowired 与 @Resource 不同

  1. @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
  2. @Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用。
  3. @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

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

3.3、使用注解开发

步骤:

  1. 导入aop的包
  2. 在配置文件中,引入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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

</beans>
  1. bean的实现

    • 配置扫描包
   <!--使用context命名空间,通知spring扫描指定包下所有的Bean,进行注解解析-->
   <context:component-scan base-package="com.k2.bean的管理.bean的装配.annotation方式"/>
  • 在指定包下编写类,增加注解
  // 相当于配置文件中 <bean id="user" class="当前注解的类"/>
  @Component("user")
  // 作用域
  @Scope("singleton")
  public class User {
  
  // 为属性赋值,不需要setter方法(属性注入)
      @Value("1")
      private int id;
      @Value("小焦同学")
      private String userName;
      @Value("123")
      private String passWord;
  
      @Override
      public String toString() {
          return "User{" +
                  "id=" + id +
                  ", userName='" + userName + '\'' +
                  ", passWord='" + passWord + '\'' +
                  '}';
      }
  }
  1. 衍生注解

    @Component三个衍生注解

    为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

    • @Repository:dao层

    • @Service:service层

    • @Controller:web层

写上这些注解,就相当于将这个类交给Spring管理装配了!

@Repository("userDao1")
public class UserDaoImpl implements UserDao {
}

@Service("userService")
public class UserServiceImpl implements UserService {
    /*
    // @Resource:引用数据类型
    @Resource(name = "userDao1")
    private UserDao userDao;
    */

    // 如果有两个类型实现类(UserDao接口有两个实现类),则需要使用@Qualifier("userDao")
    @Autowired
    @Qualifier("userDao1")
    private UserDao userDao;
}

@Controller("userController")
public class UserController {

    /*
    @Resource(name = "userService")
    private UserService userService;
    */

    // userService接口只有一个实现类,所以不需要@Qualifier()
    @Autowired
    private UserService userService;
}

@Test
public void test(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("annotation.xml");
    UserController userController = (UserController) ac.getBean("userController");
    userController.save();
}
  1. 作用域

    • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂,所有的对象都会销毁
    • prototype:多例模式。关闭工厂,所有的对象不会销毁,通过内部大垃圾回收机制回收
   // 作用域
   @Scope("singleton")
   public class User {
   }

小结:

XML与注解比较

  • XML可以适用于任何场景,结构清晰,维护方便
  • 注解不是自己提供的类使用不了,开发简单方便

**推荐方案:**xml与注解整合开发

  • xml管理bean
  • 注解完成属性注入
  • 使用过程中不用扫描包,扫描是为了类上的注解
<!--使用context命名空间,通知spring扫描指定包下所有的Bean,进行注解解析-->
    <context:component-scan base-package="com.k2.包"/>
<!--使用context命名空间,在配置文件中开启相应的注解处理器-->
<context:annotation-config/>  

作用:

  • 进行注解驱动注册,从而使注解生效
  • 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显式的向Spring注册
  • 如果不扫描包,就需要手动配置bean
  • 如果不加注解驱动,则注入的值为null!

4、使用JavaConfig实现配置类

springboot中常有

// 实体类中也就不需要再配置@Component注解,
public class User {
    @Value("张三3")
    private String name;
    @Value("18")
    private int age;
    @Autowired
    private Pet pet;
}



/**
 * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
 * 2、配置类本身也是组件
 * 3、proxyBeanMethods:代理bean的方法
 *      Full(proxyBeanMethods = true):全配置【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
 *      Lite(proxyBeanMethods = false):轻量级配置【每个@Bean方法被调用多少次返回的组件都是新创建的】
 *      组件依赖必须使用Full模式。其他默认是否Lite模式
 * 4、@Import({User.class, Filter.class})
 *      给容器中自动创建出这两个类型的组件,默认组件的名字就是全类名
 *          @Import():com.k2.springboothelloworld.pojo.User
 *          @Bean:user
 */
@Import({User.class})
@Configuration(proxyBeanMethods = true)  // 告诉SpringBoot这是一个配置类 == 配置文件xml
public class MyConfig {
    @Bean  // 给容器中添加组件,以方法名作为组件的id(bean中的id),返回类型就是组件类型(bean中的class)。
    public User user() {
        User user = new User();
        return user;        // 就是返回要注入bean的对象   返回的值,就是组件在容器中的实例
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_koen

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

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

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

打赏作者

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

抵扣说明:

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

余额充值