Spring(2)

2022-09-19

2.1bean的作用域

bean的作用域,默认是单例singleton

1.单例模式:默认的机制,只建立一个对象

<bean id="user" class="com.bo.spring02.User" c:age="18" p:name="bo" scope="singleton"/>

2.原型模式 prototype 每次从容器中getbean的时候都会产生一个新的对象

3.其余的作用域request,session,application,这些只能在web开发中用到

关于单例模式的理解:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

要点:

  • 一个类只有一个对象
  • 单例模式的类只提供私有的构造函数
  • 该类提供了一个静态的公有函数用于创建或者获取它本身的静态私有对象

通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的方法就是,让类自身负责保存它的唯一实例。这样你不用每次需要一个对象,都要去创建一个新的对象,你只需要调用这个保存的实例即可,实例变了,影响全局

为什么需要私有的构造方法?

因为我们要保证这个类不能在其他类中被多次实例化,我们知道每次实例化实际上是调用构造方法的过程,构造方法私有,其他类就调用不了,自然就不能实例化这个对象。

但其他类要用怎么办?

提供一个公共方法可以get到这个保存的实例即可

单例类(静态,类加载时就初始化了实例):

public class singleton {
    private static singleton instance = new singleton();
    private singleton(){
    }
    public static singleton getinstance(){//写静态方法才能通过类名调用而保证不实例化对象
        return instance;
    }
}

调用实例:

    public static void main(String[] args) {
        singleton instance1 = singleton.getinstance();
        singleton instance2 = singleton.getinstance();
        System.out.println(instance1==instance2);
    }

结果为true,说明两次是同一个对象

2.2自动装配bean

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

在spring中有三种装配方式:

1.xml显式配置

2.java中显示配置

3.隐式的自动装配bean【重要】

ByName自动装配

测试:

环境:一个人有两个宠物

dog:

public class dog {
    public void shout(){
        System.out.println("wang~");
    }
}

cat:

public class cat {
    public void shout(){
        System.out.println("miao~");
    }
}

people:

public class people {
    private dog dog;
    private cat cat;
    private String name;
    @
    getter/setter
    toString
}

正常装配:

    <bean id="cat" class="com.bo.spring.cat" />
    <bean id="dog" class="com.bo.spring.dog"/>

    <bean id="people" class="com.bo.spring.people">
        <property name="name" value="bo"/>
        <property name="dog" ref="dog"/>
        <property name="cat" ref="cat"/>

自动装配

    <bean id="cat" class="com.bo.spring.cat" />
    <bean id="dog" class="com.bo.spring.dog"/>

    <bean id="people" class="com.bo.spring.people" autowire="byName">
        <property name="name" value="bo"/>

byname会自动在容器上下文中查找和自己对象set方法后面的值对应的bean的id

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

比如byname就会查找id为cat和dog的bean,bytype会查找class为cat和dog的bean

2.2.小结

  • byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自己注入属性的set方法后面的值一致
  • bytype 需要保证所有bean的class唯一 ,并且和自动注入属性的类型一致

2.3 注解实现自动装配

使用注解须知:

1.导入约束,context约束

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/>

2.配置注解的支持,重要!

<context:annotation-config/>

示例:还是刚刚人和两个宠物的例子,先简单配置:

    <bean id="cat" class="com.bo.spring.cat" />
    <bean id="dog" class="com.bo.spring.dog"/>
    <bean id="people" class="com.bo.spring.people"/>

在代码中实现注解注入:

public class people {
    @Autowired
    private dog dog;
    @Autowired
    private cat cat;
}

@Autowired:加在属性和set方法上,属性加上注解后,会去上下文找与类型相同的bean实现注入,注解在属性上进行注入甚至可以省略set方法前提是在spring容器中存在,且类型一致

拓展:

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

如果@Autowired的自动装配换环境比较复杂(有多个同类型对象在容器中),使用一个注解不能完成注入,可以使用@Qualifier(value = “beanid”)来指定特定对象。

相当于默认bytype,@Qualifier辅助byname

2.4 Spring注解开发

首先还是记得配置文件导入约束和支持!

       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/>
    <!--指定要扫描的包,这个包下的注解就会生效-->
    <context:component-scan base-package="com.bo.pojo"/>

2.4.1 常用注解

@Component 组件,放在类上,说明这个类被spring管理了,就是bean!

//@Component 组件
//等价于<bean id="user" class="com.bo.pojo.User"/>
@Component
public class User {
    public String name = "bo";
}

这个时候我们就可以通过applicationcontext来getbean了,默认id为类名小写:

@Test
public void test(){
        ApplicationContext context = new 				    		  			 ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        System.out.println(user.name);
    }

@Value 放在属性或属性的set方法上,注入属性值,相当于property,但只适用于简单注入

@Component
public class User {
    @Value("bo")
    public String name ;
}

2.4.2 衍生注解

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

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

一定要记得使用注解的前提:

<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.bo"/>

2.5 使用JavaConfig实现配置

使用java的方式配置spring,不使用xml配置,交给java来做

示例:

写一个user类,即将要放到spring容器中

@Component
public class User {
    @Value("bo")
    private String name;
    
    getter/setter
        toString}

然后是config类(这个也会被spring容器托管,注册到容器中,因为它本来就是一个@Component):

@Configuration//这是一个配置类,就和之前的xml一样
@ComponentScan("com.bo")//使用这个需要在实体类上@Component
public class UserConfig {

    @Bean//注册一个bean就相当于之前写的一个bean标签
    public User getUser(){
        return new User();//返回要注入的对象
    }

关于@bean的方法:

  • 这个方法的名字相当于bean的id,getbean的时候使用这个id
  • 这个方法的返回值,就相当于bean标签的class属性
  • 使用@Bean的话 bean的id就是标注的方法名,可以使用@Bean(name=”“)来设置id

测试:

public class Mytest {
    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        User getUser = (User) context.getBean("getUser");
        User user = (User)context.getBean("user");
        System.out.println(getUser.hashCode()==user.hashCode());
    }

applicationcontext注意是Annotation,然后括号里是.class

发现hashcode不一样

注意

  • 在实体类上使用@Component并在config类上使用@ComponentScan(“com.bo”)
  • config类中在方法上使用@bean(”id”)

这两种方法效果一样,同时使用会创建两个对象,第一种getbean括号里默认是小写的实体类名,第二种getbean括号里默认是方法名或者加的id,一般使用一种即可

小结

xml与注解:

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