【spring】基础知识合集

一、什么是spring

    spring是一个轻量级的DI(IOC)和AOP的容器框架。

    轻量级:应用大小和应用开始,包括应用方式;

    DI(IOC):spring通过一种称为控制反转(IOC)的技术促进低耦合;

    AOP:面向切面,将业务逻辑从应用程序中分离;

    容器:包含并管理应用对象的生命周期和配置;

    框架:使用组件配置组合成复杂的应用,并提供很多基础的功能。

二、hello spring

    第一个hello spring程序,最少需要三个包:

    apache.commons.logging-1.1.1.jar    日志依赖包(必须)

    spring-beans-5.0.4.RELEASE.jar          spring的bean对象包

    spring-core-5.0.4.RELEASE.jar            spring的核心包

    写配置,将该配置文件放在classpath目录下,一般默认命名为applicationContext.xml,为什么要命名为这个名称呢?将在后面记录,如下:

    

然后去文档里面查找,该如何写配置文件:

写一个类,包含一个简单的方法:

public class TestBean {
    public void helloSpring() {
        System.out.println("hello spring !");
    }
}

在配置文件applicationContext.xml中配置这个TestBean:

<?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="testBean" class="cn.laiwenbo.spring.learn.TestBean">
        
    </bean>
</beans>

注意,在中间的bean的bean中,class里面的内容为该类的全类名。

接下来写测试代码,导入junit包:junit-4.11.jar    hamcrest-core-1.3.jar

@Test
    public void  testHelloSpring() {
        //第一步,加载配置文件
        Resource resouce = new ClassPathResource("applicationContext.xml");
        //第二步,拿到bean工厂
        BeanFactory beanFactory = new XmlBeanFactory(resouce);
        //第三步,拿到配置的bean,id为配置文件中写好的那个testBean
        TestBean testBean = (TestBean) beanFactory.getBean("testBean");
        //第四步,调用bean中的方法
        testBean.helloSpring();
    }

输出结果:

说明hello spring 整个流程成功。

三、BeanFactory的认识

    ①获取bean的方式

    那么在hello spring 中使用的BeanFactory有什么特点呢?其实,beanFactory获取bean的方式有三种:

    第一种:通过bean的id来获取bean(如果两个bean的id相同,报错

TestBean testBean = (TestBean) beanFactory.getBean("testBean");

    第一种:通过id和对象类型class来拿到bean,不需要强转(如果两个bean的id和类型相同,报错

    TestBean testBean = beanFactory.getBean("testBean",TestBean.class);

    第三种:直接通过类型来拿到bean(如果两个bean的类型相同,报错

TestBean testBean = beanFactory.getBean(TestBean.class);

    ②BeanFactory常用方法

    

public void testBeanFactory() {
        Resource resource = new ClassPathResource("applicationContext.xml");
        BeanFactory beanFactory = new XmlBeanFactory(resource);
        //查看是不是包含某个bean
        boolean containsBean = beanFactory.containsBean("testBean");
        System.out.println(containsBean); //输出true
        //是否是单例的(默认是单例的)
        boolean singleton = beanFactory.isSingleton("testBean");
        System.out.println(singleton); //输出true
        //获取bean的类型
        Class<?> aClass = beanFactory.getType("testBean");
        System.out.println(aClass); //输出cn.laiwenbo.spring.learn.TestBean
        //获取bean的别名
        String[] aliases = beanFactory.getAliases("testBean");
    }

四、ApplicationContext的认识

      ①认识ApplicationContext

    ApplicationContext是spring的一个核心对象,它也是实现了BeanFactory这个接口,因此可以说ApplicationContext也是一个Bean工厂。ApplicationContext的优势在于:

    ①提供了文本信息的解析工具,包括I18N的支持。

    ②提供了载入文件资源的通用方法。

    ③提供了发送事件的功能。

要使用ApplicationContext还需要导入额外的两个包:spring-context    spring-expression

public void applicationContextTest() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    TestBean bean = applicationContext.getBean("testBean", TestBean.class);
    bean.helloSpring();
}

    ②ApplicationContext和BeanFactory的区别

        解释:ApplicationContext是BeanFactory的子类,具有更多的方法和功能。

        重点:ApplicationContext是在读取的时候就创建Bean对象,而BeanFactory是在使用的时候才创建Bean对象(懒加载)。

        拓展:在使用ApplicationContext的时候,也可以配置成想BeanFactory一样的懒加载。

        实例一:让所有的Bean都变成懒加载

<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" default-lazy-init="true">

</beans>default-lazy-init="true">

</beans>

        实例二:让一个Bean变成懒加载

<bean id="testBean" class="cn.laiwenbo.spring.learn.TestBean" lazy-init="true"></bean>lazy-init="true"></bean>

        如果在Beans上配置了懒加载,但是又想里面某些Bean不是懒加载:

<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" default-lazy-init="true">
    <bean id="testBean" class="cn.laiwenbo.spring.learn.TestBean" lazy-init="false"></bean>
</beans>default-lazy-init="true">
    <bean id="testBean" class="cn.laiwenbo.spring.learn.TestBean" lazy-init="false"></bean>
</beans>

五、Spring的注解测试

    spring提供了自己的测试模块,使用Spring的测试,需要导入包:spring-aop和spring-test

    第一种:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SpringTestModule {

    //自动注入
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void getBean() {
        TestBean testBean = applicationContext.getBean("testBean", TestBean.class);
        testBean.helloSpring();
    }
}

这种方式需要在SpringTestModule类的目录下加上配置文件,且名称为:类名-context.xml

    第二种:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTestModule {

    //自动注入
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void getBean() {
        TestBean testBean = applicationContext.getBean("testBean", TestBean.class);
        testBean.helloSpring();
    }
}

这种不需要在类名下有配置文件,但是要配置文件在classpath路径下,且标签发生了变化:

@ContextConfiguration("classpath:applicationContext.xml")

六、Spring中的Bean

    ①在配置bean的时候,可以配置bean是单例还是多例。

    多例:

<bean id="testBean1" class="cn.laiwenbo.spring.learn.TestBean" scope="prototype"></bean>

    单例,单例是默认的模式

<bean id="testBean1" class="cn.laiwenbo.spring.learn.TestBean" scope="prototype"></bean>

    ②spring的生命周期管理

    创建一个具有初始化和销毁的bean,并配置初始化方法和销毁方法:

public class SpringLive {

    public SpringLive(){
        System.out.println("构造方法执行...");
    }

    public void init() {
        System.out.println("初始化方法执行...");
    }

    public void service(){
        System.out.println("service方法执行...");
    }

    public void destroy(){
        System.out.println("销毁方法执行...");
    }
}
<bean id="testBean2" class="cn.laiwenbo.spring.learn.SpringLive" init-method="init" destroy-method="destroy"></bean>

输出:

构造方法执行...
初始化方法执行...
service方法执行...

销毁方法执行...

需要注意的是,如果将bean配置成多例,那么spring将不会监控到销毁的方法

 

<bean id="testBean2" class="cn.laiwenbo.spring.learn.SpringLive" init-method="init" destroy-method="destroy" scope="prototype"></bean>

输出:

构造方法执行...
初始化方法执行...
service方法执行...

六、spring的注入

    ①xml加set注入

    bean:

public class UserDao {
    public void userDao(){
        System.out.println("userDao...");
    }
}
public class UserService {
    private UserDao userDao;

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

    public void userService() {
        System.out.println("userService...");
        userDao.userDao();
    }
}
public class UserController {
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void userController(){
        System.out.println("userController...");
        userService.userService();
    }
}

    配置文件:

    <bean id="userDao" class="cn.laiwenbo.spring.learn.di.UserDao"></bean>
    <bean id="userService" class="cn.laiwenbo.spring.learn.di.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>
    <bean id="userController" class="cn.laiwenbo.spring.learn.di.UserController">
        <property name="userService" ref="userService"></property>
    </bean>

输出:

userController...
userService...
userDao...

需要注意的是,<property name="userDao" ref="userDao"></property>参数设置,其中,name需要与setXXX中的这个名字首字母小写一致,比如在UserService中,需要注入userDao,那么需要对应的set方法:

 

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

那么这个方法名setUserDao去掉set再将首字母小写,就是我们property 中的name的值。

而ref的值就是已经配置bean的id的值。

    ②继承的实现

    在spring的xml注入中,有时候需要在多个bean中使用同一个bean作为参数,那么可以spring的集成配置:

    三个bean,其中UserDao和EmployeeDao都需要使用SqlSessionFactory,如下:

public class SqlSessionFactory {
    public void openSession() {
        System.out.println("我是假的sqlSessionFactory....");
    }
}
public class UserDao {
    private SqlSessionFactory sessionFactory;
    public void setSessionFactory(SqlSessionFactory sessionFactory){
        this.sessionFactory = sessionFactory;
    }
    public void save(){
        sessionFactory.openSession();
    }
}
public class EmployeeDao {
    private SqlSessionFactory sessionFactory;
    public void setSessionFactory(SqlSessionFactory sessionFactory){
        this.sessionFactory = sessionFactory;
    }
    public void save() {
        sessionFactory.openSession();
    }
}

    配置文件,注意id为baseDao的这个配置,由于abstract=“true”表示为抽象的,所以没有class的属性,在

需要使用baseDao的bean中,加上parent="父bean"就可以了。

    <bean id="baseDao" abstract="true">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <bean id="sessionFactory" class="cn.laiwenbo.spring.learn.extendss.SqlSessionFactory"></bean>

    <bean id="userDao" class="cn.laiwenbo.spring.learn.extendss.UserDao" parent="baseDao"></bean>

    <bean id="employeeDao" class="cn.laiwenbo.spring.learn.extendss.EmployeeDao" parent="baseDao"></bean>

    ③注入普通属性

    有时候,需要在一个bean中注入普通属性(String,int,double),注入普通属性案例如下:

public class UserBean {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "UserBean{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
<bean id="userBean" class="cn.laiwenbo.spring.learn.extendss.UserBean">
        <property name="id" value="1"></property>
        <property name="name" value="abc"></property>
    </bean>

    ④获取dataSource

第一种,直接将配置写在xml文件里面。

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <!--GMT%2B8代表: 东八区-->
        <property name="url" value="jdbc:mysql://localhost:3306/lwb?serverTimezone=GMT%2B8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
@Autowired
    private DataSource dataSource;
    @Test
    public void getDataSource() throws SQLException {
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement("select * from user");
        ResultSet resultSet = statement.executeQuery();
        while (resultSet.next()) {
            System.out.println(resultSet.getString(2));
        }
    }

第二种,将配置信息写在properties文件里面。其中system-properties-mode="NEVER"表示不使用系统用户。

<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"></context:property-placeholder>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <!--GMT%2B8代表: 东八区-->
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
jdbc.properties文件:
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/lwb?serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=root

解释:system-properties-mode="NEVER"表示不使用系统用户。

由于在spring中,有些特定的关键字,比如username,如果将配置文件写成如下的格式:

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/lwb?serverTimezone=GMT%2B8
username=root
password=root
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${driverClassName}"></property>
        <!--GMT%2B8代表: 东八区-->
        <property name="url" value="${url}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>

运行测试报错:

用户为Administrator,密码错误,说明spring自动使用了我操作系统的用户名,所以会报错,注意这样的情况是没有加system-properties-mode="NEVER"的情况才会出现。因此,在配置的时候,最好是给配置信息加上前缀,比如jdbc.username

⑤构造器注入

    构造器注入有多中方式,但是构造器注入遇到的场景比较少,很多情况是在用别人写好的类的时候才会用到。

1、按照构造器参数的顺序注入

    构造器注入,写了两个javabean:

public class ConstructorDI {
    private int age;
    private String name;

    public ConstructorDI(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "ConstructorDI{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
public class ConstructorDI2 {
    private int age;
    private String name;
    private Info info;

    public ConstructorDI2(int age, String name, Info info) {
        this.age = age;
        this.name = name;
        this.info = info;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "ConstructorDI{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", info=" + info +
                '}';
    }
}
 <!--按照索引注入,起始索引为0-->
    <bean id="constructorDI1" class="cn.laiwenbo.spring.learn.di2.ConstructorDI">
        <constructor-arg index="0" value="1" />
        <constructor-arg index="1" value="lwb"/>
    </bean>

    <!--按照参数名称注入-->
    <bean id="constructorDI2" class="cn.laiwenbo.spring.learn.di2.ConstructorDI">
        <constructor-arg name="age" value="2" />
        <constructor-arg name="name" value="lwb"/>
    </bean>

    <!--根据类型注入-->
    <bean id="constructorDI3" class="cn.laiwenbo.spring.learn.di2.ConstructorDI">
        <constructor-arg type="int" value="2" />
        <constructor-arg type="java.lang.String" value="lwb"/>
    </bean>

    <!--注入自定义的对象,这种方式,外部不能引用Info这个bean-->
    <bean id="constructorDI4" class="cn.laiwenbo.spring.learn.di2.ConstructorDI2">
        <constructor-arg index="0" value="2" />
        <constructor-arg index="1" value="lwb"/>
        <constructor-arg index="2">
            <bean class="cn.laiwenbo.spring.learn.di2.Info">
                <constructor-arg index="0" value="波波"/>
            </bean>
        </constructor-arg>
    </bean>

    <!--注入自定义的对象,这种方式,外部可以引用info这个bean-->
    <bean id="info" class="cn.laiwenbo.spring.learn.di2.Info">
        <constructor-arg index="0" value="波波"/>
    </bean>
    <bean id="constructorDI5" class="cn.laiwenbo.spring.learn.di2.ConstructorDI2">
        <constructor-arg index="0" value="2" />
        <constructor-arg index="1" value="lwb"/>
        <constructor-arg index="2" ref="info"/>
    </bean>

2、其他类型注入

    数组注入,两种方式:

<property name="arrays" value="23,df,dsf" />
<property name="arrays">
	<array>
		<value>xxx</value>
		<value>tyy</value>
		<value>zzz</value>
	</array>
</property>

List注入:

<property name="list">
	<list>
		<value>xxx</value>
		<value>aaa</value>
		<value>bbbb</value>
	</list>
</property>

Set注入:

<property name="set">
	<set>
		<value>xxx</value>
		<value>aaa</value>
		<value>bbbb</value>
	</set>
</property>

List<Bean>注入:

<property name="otherBeanList">
	<list>
		<bean class="cn.lwb.OtherBean" />
		<bean class="cn.lwb.OtherBean" />
		<ref bean="otherBean" />
		<ref bean="otherBean" />
	</list>
</property>

Set<Bean>注入:

<property name="otherBeanSet">
	<set>
		<bean class="cn.lwb.OtherBean" />
		<bean class="cn.lwb.OtherBean" />
		<ref bean="otherBean" />
		<ref bean="otherBean" />
	</set>
</property>

Map注入:

<property name="map">
	<map>
		<entry key="xx" value="value1"></entry>
		<entry key="yy" value="value2"></entry>
	</map>
</property

配置一个Properties对象:

<!-- 方式一:简单,不支持中文 -->
<property name="props1">
	<value>
		hibernate.dialect=org.hibernate.dialect.HSQLDialect
		hibernate.driverClassName=com.mysql.jdbc.Driver
	</value>
</property>
<!-- 方式二:支持中文 -->
<property name="props2">
	<props>
		<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
		<prop key="hibernate.driverClassName">com.mysql.jdbc.Driver中文 </prop>
	</props>
</property>

⑥xml版自动注入

首先创建三个javabean对象:

public class UserController {
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void get() {
        System.out.println("userController get ...");
        userService.get();
    }
}
public class UserService {
    private UserDao userDao;

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

    public void get() {
        System.out.println("userService get ...");
        userDao.get();
    }
}
public class UserDao {
    public void get(){
        System.out.println("userDao get ...");
    }
}

然后是配置xml的自动注入:

第一种,根据javabean的类型来注入,注意在beans后面的default-autowire="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" default-autowire="byName">

    <bean id="userDao" class="cn.laiwenbo.spring.learn.autowireXML.UserDao"></bean>
    <bean id="userService" class="cn.laiwenbo.spring.learn.autowireXML.UserService"></bean>
    <bean id="userController" class="cn.laiwenbo.spring.learn.autowireXML.UserController"></bean>
</beans>

第二种,根据名称来注入,注意同样是setXX()这个方法的规则来注入的,也就是说bean的id需要与XX首字母小写之后的一直:default-autowire="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" default-autowire="byName">

    <bean id="userDao" class="cn.laiwenbo.spring.learn.autowireXML.UserDao"></bean>
    <bean id="userService" class="cn.laiwenbo.spring.learn.autowireXML.UserService"></bean>
    <bean id="userController" class="cn.laiwenbo.spring.learn.autowireXML.UserController"></bean>
</beans>

当然,在总的beans配置之后,也可以单独的为某些bean配置,比如:

<?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" default-autowire="byName">

    <bean id="userDao" class="cn.laiwenbo.spring.learn.autowireXML.UserDao"></bean>
    <bean id="userService" class="cn.laiwenbo.spring.learn.autowireXML.UserService"></bean>
    <bean id="userController" class="cn.laiwenbo.spring.learn.autowireXML.UserController" autowire="byType"></bean>
</beans>

在上面,单独的为userController配置为autowire="byType"。

总结:如果用byType类型必须保证唯一,如果用byName必须保证名字唯一。因此,代码必须保证规范。

⑦全注解配置

@Repository
public class UserDao {
    public void get(){
        System.out.println("userDao get ...");
    }
}
public class UserDao {
    public void get(){
        System.out.println("userDao get ...");
    }
}
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public void get() {
        System.out.println("userService get ...");
        userDao.get();
    }
}
public class UserService {
    @Autowired
    private UserDao userDao;

    public void get() {
        System.out.println("userService get ...");
        userDao.get();
    }
}
@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void get() {
        System.out.println("userController get ...");
        userService.get();
    }
}
public class UserController {
    @Autowired
    private UserService userService;

    public void get() {
        System.out.println("userController get ...");
        userService.get();
    }
}
<?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:component-scan base-package="cn.laiwenbo.spring.learn.anno"/>
    <!--开始注解支持,上面已经开启了注解支持,这句是为了兼容spring3.0以及之前的版本
        spring3.0之前,这句必须要
    -->
    <context:annotation-config />
</beans>
扫描具有注解的包,自动开始注解支持-->
    <context:component-scan base-package="cn.laiwenbo.spring.learn.anno"/>
    <!--开始注解支持,上面已经开启了注解支持,这句是为了兼容spring3.0以及之前的版本
        spring3.0之前,这句必须要
    -->
    <context:annotation-config />
</beans>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AnnoAutowireTest {
    @Autowired
    private UserController userController;
    @Test
   public void test() {
        userController.get();
   }
}

注意,在上面bean中,UserDao上面加上了注解@Respository,在UserService上面加上了注解@Service,

在UserController上面加上了Controller,其实这三个注解都表示要将该bean交给Spring来管理,其功能完全是一样的。其实这样功能完全一样的注解共有四个,还有一个@Component,既然功能完全一样为什么要写四个出来呢?其实,这是给程序员看的,具体情况如下:

@Respository : 表示该bean为操作仓库的类,既操作数据库的。

@Service : 表示Service层。

@Controller :表示控制层。

@Component :表示普通javabean,既不在上面三个范围之中。

七、自动注入细节

    在spring自动注入中, 有时候会遇见一个接口有多个实现类的情况,遇到这样的情况,需要注意一下一些细节。

    首先一个公共的抽象接口:

public interface IBaseDao {
    public void save();
}

    然后一个类实现该接口:

@Repository
public class UserDao implements IBaseDao {
    @Override
    public void save() {
        System.out.println("我是userDao....");
    }
}

配置文件如下:    

<!--注解扫描位置-->
    <context:component-scan base-package="cn.laiwenbo.spring.learn.di3"/>
    <!--兼容性设置,开启注解-->
    <context:annotation-config/>

经过测试可以发现,输出为我是userDao...

@RunWith(SpringJUnit4ClassRunner.class)
@Configuration
public class Test {
    @Autowired
    private IBaseDao myUserDao;

    @org.junit.Test
    public void test01() {
        myUserDao.save();
    }
}

需要注意的是,在测试类中,自动注入的类型仅仅是接口的类型:

 

@Autowired
private IBaseDao myUserDao;

那么为什么可以找到UserDao中的save()方法呢?其实是通过类型来找到的实现类,因为UserDao实现了IBaseDao 既然这里是通过类型来找到的,如果有多个类实现了IBaseDao呢?结果会怎么样呢?

另一个实现了IBaseDao的类:

@Repository
public class OtherDao implements IBaseDao{
    @Override
    public void save() {
        System.out.println("otherDao....");
    }
}

结果会报错,找到两个类型的Dao

上面就充分的说明了,spring是按照接口的类型去找的实现子类,这里就是矛盾所在,如果一个接口被多个类实现了,那么这样的操作方式就会报错了。该如何解决呢? 将注入的名字改为实现类的类名+首字母小写

@RunWith(SpringJUnit4ClassRunner.class)
@Configuration
public class Test {
    @Autowired
    private IBaseDao userDao;
    @Autowired
    private IBaseDao otherDao;

    @org.junit.Test
    public void test01() {
        userDao.save();
        otherDao.save();
    }
}

这里注入的名字需要特别注意,是按照实现类的类名来的。说明spring首先按照类型来查找,然后在按照类名的规则来查找的。

但是有没有办法不按照类名来,也可以找到我们想找的实现类呢?当然是有的,在实现类的注解上,加上名称就可以了:

@Repository("oDao")//指定一个名称

public class OtherDao implements IBaseDao{
    @Override
    public void save() {
        System.out.println("otherDao....");
    }
}
@Repository("uDao")//指定一个名称
public class UserDao implements IBaseDao {
    @Override
    public void save() {
        System.out.println("我是userDao....");
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@Configuration
public class Test {
    @Autowired
    private IBaseDao uDao; //指定的名陈
    @Autowired
    private IBaseDao oDao; //指定的名称

    @org.junit.Test
    public void test01() {
        uDao.save();
        oDao.save();
    }
}

或者:

@RunWith(SpringJUnit4ClassRunner.class)
@Configuration
public class Test {
    @Autowired
    @Qualifier("uDao") //限定需要注入的类是哪一个,uDao在对应的类上已经配置,这样下面的变量可以随意命名了

    private IBaseDao userDao;
    @Autowired
    @Qualifier("oDao")//限定需要注入的类是哪一个,oDao在对应的类上已经配置,这样下面的变量可以随意命名了
    private IBaseDao otherDao;

    @org.junit.Test
    public void test01() {
        userDao.save();
        otherDao.save();
    }
}

这里需要额外知道的是@Resource标签:

@RunWith(SpringJUnit4ClassRunner.class)
@Configuration
public class Test {
    @Autowired
    @Qualifier("uDao")
    private IBaseDao userDao;
    /*@Autowired
    @Qualifier("oDao")
    private IBaseDao otherDao;*/
    @Resource(name="oDao")  //这里的配置等同于 @Autowired    @Qualifier("oDao")这两个标签
    private IBaseDao otherDao;
    @org.junit.Test
    public void test01() {
        userDao.save();
        otherDao.save();
    }
}

@Autowired是spring提供的标签,而@Resource是jdk自带的,他们的作用是完全一样的,但是使用细节上还是有一定区别的。另外,在使用过程中,一般不用@Resource标签,因为使用spring的时候,最好是使用和spring一套的东西,规范代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值