使用注解配置Bean
第一件要做的事情就是,添加spring-aop.jar包到项目中。
Spring推荐使用4个注解来描述类:
@Component:组件
@Repository:持久化层
@Service:业务层
@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.*">
编写一段测试代码:
getBean的参数,默认为类的全名,但首字母小写。可是如果在注解中写了别名,就需要用别名来getBean,比如上面的userRepositoryImpl类。
context:component-scan还可以对扫描的包进行细致的过滤。
可以在元素中加入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..."); } }
结果显示正常。
其中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); } }
报错,不能自动装载字段,修改一下注释:
@Autowired(required=false) private TestObject testObject;
不再报错了,允许描述的字段为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..."); } }
在进行测试,结果发生了异常:
有几种方式解决,第一个是为其中的某一个类设置@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(); } }
泛型的依赖注入
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描述即可,测试一下:
以上,就是使用注解描述bean的基本内容。