上一篇SpringFramework学习-(9)基于注解配置bean
介绍了如何从配置文件配置bean到通过注解配置bean的转移,中间用到了几个常用的注解。Spring提供了很多的注解,没法一一的都介绍。本篇将介绍一下常用的各个注解都是什么意思,该在哪里使用这个注解。
1.@Component
@Controller
,@Serivce
,@Repository
,@Component
四个注解通常被用来标记类。如果某个类的头上带有这些特定的注解,通过<context:component-scan base-package=” ”/>
扫描就可以将这些类注册到SpringIoC容器之中。
@Component
是所有受Spring 管理组件的通用形式,仅仅表示一个组件 (Bean) ,可以作用在任何层次,@Component
注解可以放在类的头上,但是实际的运用中@Component
不推荐使用。
有了这个通用组件@Component
,为了区分不同层面上的组件,Spring提供了其他@Controller
,@Serivce
,@Repository
分别用于标识控制层,业务层,数据层的bean。
很多人包括笔者之前也纠结于这几个注解到底有什么区别呢?
带着疑问,打开这几个注解的源码可以看到内部实际并没有任何的区别,都只有简单的一行代码。同时我们也看到了这些注解也都是通过@Component
组件进行标记的。
String value() default "";
但是我们还是没有找到他们之间的区别是什么 ,于是我们来到Spring的官方文档,看看官方文档是怎么说的:
|————————————————————————————————————————–
The @Repository
annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions as described in Section 19.2.2, “Exception translation”.
Spring provides further stereotype annotations: @Component
, @Service
, and @Controller
. @Component
is a generic stereotype for any Spring-managed component. @Repository
, @Service
, and @Controller
are specializations of @Component
for more specific use cases, for example, in the persistence, service, and presentation layers, respectively. Therefore, you can annotate your component classes with @Component
, but by annotating them with @Repository
, @Service
, or @Controller
instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. It is also possible that @Repository
, @Service
, and @Controller
may carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component
or @Service
for your service layer, @Service
is clearly the better choice. Similarly, as stated above, @Repository
is already supported as a marker for automatic exception translation in your persistence layer.
@Component
组件是任何spring管理组件的通用原型。 @Repository
、@Service
和@Controller
是针对更具体的用例(例如,在持久性、服务和表示层)中的@component
的专门化。因此,您可以使用@Component
来注释您的组件类,但是通过使用@Repository
、@Service
或@Controller
来注解它们,您的类更适合于使用工具进行处理或与面向切面Aspects关联,例如,这些原型注解为切入点提供了理想的目标。在Spring框架的未来版本中,@Repository
、@Service
和@Controller
也可能带有附加的语义。因此,如果您选择使用@Component
或@Service
为您的服务层,@Service
显然是更好的选择。类似地,如上所述,在您的持久层中,@Repository
已经作为自动异常转换的标记支持。
—————————————————————————————————————————|
官方文档说的再清楚不过了。这几个主机本质上并没有区别,只是做为各层级的标记。方便面向切面指定切入点,在未来的Spring版本升级中可能会给各个注解添加语义,同时对异常处理做了一些标记支持。
所以到此我们就不用再纠结于他们之间的区别了。
通过xml配置文件,我们可以配置bean的作用域,加载方式等属性,通过注解也可以配置:
@Scope(“prototype”),@Scope(“singleton”)
@Lazy(true),@Lazy(false)
2.@Configuration和@Bean
这个一直是比较不好理解的东西,官方文档给出的例子是
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
等同于
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
怎么理解呢,实际上就是把@Configuration
标注的类看做是一个IOC容器,而把类里面@Bean
标注的方法看作是IOC容器里面的bean。
还是不能够理解是吧,那么我们写个小例子运行一下看看:
有一个Person类
package com.jd.annotation2;
public class Person {
private int id;
private String userName;
private String loginName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public Person() {
System.out.println("Person constructor...");
}
}
有一个UserService和UserServiceImpl实现
package com.jd.annotation2.service;
public interface UserService {
public void addInt(int a,int b);
}
package com.jd.annotation2.service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.jd.annotation2.dao.UserDao;
@Service("userService")
@Scope("prototype")
@Lazy(true)
public class UserServiceImpl implements UserService{
public void addInt(int a ,int b) {
System.out.println("userService ... addInt");
}
}
有一个类提供了两个方法,分别提供Person和UserServiceImpl
package com.jd.annotation2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.jd.annotation2.service.UserService;
import com.jd.annotation2.service.UserServiceImpl;
@Configuration
public class AppCig {
@Bean
public Person getPerson(){
return new Person();
}
@Bean
public UserService getUserService(){
return new UserServiceImpl();
}
}
测试一下:
package com.jd.annotation2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jd.annotation2.service.UserService;
public class AnnotationTest2 {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("springannotation2.xml");
Person p = (Person)ac.getBean("getPerson");
System.out.println(p);
UserService us = (UserService)ac.getBean("getUserService");
System.out.println(us);
}
}
结果:
Person constructor…
com.jd.annotation2.Person@65466a6a
com.jd.annotation2.service.UserServiceImpl@4ddced80
我们发现我们可以直接在IOC容器之中直接调用getPerson()和getUserService()方法。@Bean
注释用于指示方法实例化、配置和初始化一个新的对象,由Spring IoC容器管理。对于熟悉Spring的<bean/>
XML配置的人来说,@Bean
注释与<bean/>
元素具有相同的作用。当然也可以使用@Bean
与@Component
配合使用,但是大多数情况下还是使用@Bean
与@Configuration
组合使用。
3.@PostConstruct和@PreDestroy
前面在Bean的特性中介绍到Bean的声明周期。通过注解也可以完成Bean声明周期的管理。
@PostConstruct
用于指定初始化方法(用在方法上)
@PreDestory
用于指定销毁方法(用在方法上)
看例子:
userDaoImpl添加两个方法postConstruct1()和preDestroy1()
@Repository("userDao")
public class UserDaoImpl implements UserDao{
public void add(int a, int b) {
int result = a+b;
System.out.println("调用加法操作,result:"+result);
}
public void pur(int a, int b) {
int result = a-b;
System.out.println("调用减法操作,result:"+result);
}
@PostConstruct
public void postConstruct1(){
System.out.println("userDao ... postConstruct1");
}
@PreDestroy
public void preDestroy1(){
System.out.println("userDao ... preDestroy1");
}
}
userServiceImpl添加两个方法postConstruct1()和preDestroy1()
package com.jd.annotation2.service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.jd.annotation2.dao.UserDao;
@Service("userService")
@Scope("prototype")
@Lazy(true)
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
public void addInt(int a ,int b) {
userDao.add(a, b);
}
@PostConstruct
public void postConstruct1(){
System.out.println("userService ... postConstruct1");
}
@PreDestroy
public void preDestroy1(){
System.out.println("userService ... preDestroy1");
}
}
测试:
public class AnnotationTest {
private ClassPathXmlApplicationContext ac = null;
private UserService userService = null;
{
ac = new ClassPathXmlApplicationContext("springannotation2.xml");
userService = ac.getBean(UserService.class);
}
@Test
public void testAnnotation(){
userService.addInt(1, 2);
ac.close();
}
}
结果:
userDao … postConstruct1
userService … postConstruct1
调用加法操作,result:3
[org.springframework.context.support.ClassPathXmlApplicationContext]Closing org.springframework.context.support.ClassPathXmlApplicationContext@31b7dea0: startup date [Fri Dec 29 14:27:09 CST 2017]; root of context hierarchy
userDao … preDestroy1