学习Spring(八) -- Spring使用注解配置bean

使用注解配置Bean

    第一件要做的事情就是,添加spring-aop.jar包到项目中。

    Spring推荐使用4个注解来描述类:

  1. @Component:组件

  2. @Repository:持久化层

  3. @Service:业务层

  4. @Controller:控制器层

    创建一个user的持久层、业务层和控制器层,并使用注解进行依赖注入:

@Component
public class TestObject { } // 建立一个组件。
public interface UserRepository {
    void save();
} // 建立一个持久化层的接口。
@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository {
    @Override
    public void save() {
        System.out.println("User Repository Save...");
    }
}
// 持久化接口的实现类,指定@Repoitory注解。

    @Repository("userRepository"):@Repository可以添加一个Name参数,意思<bean id="..." />一样。

@Service
public class UserService {
    public void add() {
        System.out.println("user service add...");
    }
} // 业务层的代码。
@Controller
public class UserController {
    public void execute(){
        System.out.println("user controller execute...");
    }
} // 控制器层代码。

    使用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:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/util 
http://www.springframework.org/schema/util/spring-util-4.2.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    <!-- 指定spring IOC扫描的package -->
    <context:component-scan base-package="cn.net.bysoft.lesson6">
    </context:component-scan>
</beans>

    context:component-scan的base-package属性用来告诉扫描器,扫描哪个包里的文件,可以使用*通配符:

<context:component-scan base-package="cn.net.bysoft.*">

    编写一段测试代码:

学习Spring(八) -- Spring使用注解配置bean_第1张图片

    getBean的参数,默认为类的全名,但首字母小写。可是如果在注解中写了别名,就需要用别名来getBean,比如上面的userRepositoryImpl类。

    context:component-scan还可以对扫描的包进行细致的过滤。

学习Spring(八) -- Spring使用注解配置bean_第2张图片

    可以在元素中加入context:exclude-filter和context:include-filter,前者是排除要扫描的包中的某某某,后者是包含要扫描的包中的某某某,做一个例子使用一下。

    上面的4个对象都在cn.net.bysoft.lesson6这个包中,但如果想排除掉TestObject该怎么做呢?如下:

<context:exclude-filter type="annotation" 
                        expression="org.springframework.stereotype.Component"/>

    上面这段代码代表移除所有的@Component注解。

    如果有多个类被@Component注解所描述,不想一次都排除掉,可以修改type="assignable",在expression处填写全类名:

<context:exclude-filter type="assignable" expression="cn.net.bysoft.lesson6.TestObject"/>

    包含的用法与排除是一样的,但是有一个细节需要注意,就是context:component-scan元素的use-default-filters属性,这个属性是默认的扫描器过滤器是否启动,模式是等于true的,如果需要用context:include-filter,需要将这个属性设置为false:

<context:component-scan base-package="cn.net.bysoft.lesson6" use-default-filters="false">
    <context:include-filter type="assignable" expression="cn.net.bysoft.lesson6.TestObject"/>
</context:component-scan>

使用注解配置Bean之间的依赖注入

    通常,我们做一个对象的CRUD,都是在Controller层调用Service层的方法,在Service层调用Dao层的方法,那么模拟这个做法,对上面的代码进行修改,模拟类之间的引用:

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    
    public void execute(){
        System.out.println("user controller execute...");
        userService.add();
    }
}

    设置bean之前的引用,使用@Autowired(自动装配)注解进行描述,Spring会去匹配类型兼容的bean,可以用来描述字段、构造函数和setter方法。把接下来的代码补全:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public void add() {
        System.out.println("user service add...");
        userRepository.save();
    }
}
package cn.net.bysoft.lesson6;

import org.springframework.stereotype.Repository;

@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository {

    @Override
    public void save() {
        System.out.println("User Repository Save...");
    }
}

学习Spring(八) -- Spring使用注解配置bean_第3张图片

    结果显示正常。

    其中Controller类、Service类和Repository类都被注解描述了,但是如果用@Autowired注解去描述没有被注解描述的类是会报错的,需要在@Autowired中设置required=false。

    我们把之前的TestObject类的注解去掉:

package cn.net.bysoft.lesson6;

public class TestObject { }

    然后在Controller类中使用它,运行程序:

@Controller
public class UserController {
    @Autowired
    private UserService userServicea;
    
    @Autowired()
    private TestObject testObject;
    
    public void execute(){
        System.out.println("user controller execute...");
        userServicea.add();
        System.out.println("打印testObject: " + testObject);
    }
}

学习Spring(八) -- Spring使用注解配置bean_第4张图片

    报错,不能自动装载字段,修改一下注释:

@Autowired(required=false)
private TestObject testObject;

学习Spring(八) -- Spring使用注解配置bean_第5张图片

    不再报错了,允许描述的字段为null。

    下面的问题,如果在注解中,一个接口被多个类实现,那么自动装配应该去装配哪个类呢,比如上面的代码中,我们的UserRepository是一个Interface,被UserRepositoryImpl实现,现在,我在创建一个类实现UserRepository:

@Repository()
public class UserRedisRepositoryImpl implements UserRepository {

    @Override
    public void save() {
        System.out.println("User Redis Repository Save...");
    }
}

    然后删除掉UserRepositoryImpl的别名,把@Repository("userRepository")改成@Repository:

@Repository
public class UserRepositoryImpl implements UserRepository {

    @Override
    public void save() {
        System.out.println("User Repository Save...");
    }

}

    在进行测试,结果发生了异常:

学习Spring(八) -- Spring使用注解配置bean_第6张图片

    有几种方式解决,第一个是为其中的某一个类设置@Repository("userRepository"),还可以使用@Qualifier("userRedisRepositoryImpl")来在声明字段时装配指定类型的

@Service
public class UserService {
    @Autowired
    @Qualifier("userRedisRepositoryImpl")
    private UserRepository userRepository;

    public void add() {
        System.out.println("user service add...");
        userRepository.save();
    }
}

学习Spring(八) -- Spring使用注解配置bean_第7张图片

泛型的依赖注入

package cn.net.bysoft.lesson6;

import org.springframework.beans.factory.annotation.Autowired;

public class BaseService<T> {
    @Autowired
    protected BaseRepository<T> baseRepository;
    
    public void add(T t) {
        System.out.println("add...");
        baseRepository.save(t);
    }
}
package cn.net.bysoft.lesson6;

public class BaseRepository<T> {
    public void save(T t) {
        System.out.println(t.getClass() + " save...");
    }
}
public class Dept {}
public class Role {}
@Service
public class DeptService extends BaseService<Dept> { }
@Repository
public class DeptRepository extends BaseRepository<Dept> { }
@Service
public class RoleServiceextends BaseService<Role> {}
@Repository
public class RoleRepository extends BaseRepository<Role> {}

    先粘贴出来了八个类,第一个类是泛型Service,第二个类是泛型Repository,第三个和第四个类是两个实体类,第五个第六个是Dept的业务类与持久化类,最后两个是Role的业务类与持久化类。

    可以看到,除了两个Base类之外,与之前的配置是一样的,关键在于Base类的配置。

    Base类不需要对类进行注解,因为它是用来被继承的,所以由继承它的子类使用类注解。

    只需要对引用的类进行@Autowired描述即可,测试一下:

学习Spring(八) -- Spring使用注解配置bean_第8张图片

    以上,就是使用注解描述bean的基本内容。

你可能感兴趣的:(学习Spring(八) -- Spring使用注解配置bean)