Spring组件扫描、注解

1. 前2天小结

  1. 【理解】通过Spring获取对象的3种条件:无参构造方法、静态工厂方法、实例方法;

  2. 【理解】由Spring管理的对象的作用域及生命周期:单例、懒加载、生命周期方法;

  3. 【重要】通过SET方式注入属性的值,理解value和ref的使用;

  4. 【了解】通过构造方法注入属性的值;

  5. 【了解】注入集合类型的属性的值,包括:List / Set / Map;

  6. 【重要】注入Properties类型的属性的值,读取*.properties文件;

  7. 【理解】自动装配的作用,取值为byName与byType的特性;

  8. 【重要】Spring表达式

2. Spring注解(Annotation)

2.1. 基本概念

例如@Override就是注解,在Spring中定义了一些注解,可以取代在Spring的XML文件中的配置!

2.2. 通过Spring获取对象

案例目标:创建cn.tedu.spring.dao.UserDao类,然后,创建cn.tedu.spring.test.SpringTest类,通过Spring获取UserDao的对象。

在Spring中,有几种通用注解:

  • @Component

  • @Controller

  • @Service

  • @Repository

这些注解是添加在类的声明之前的,表示这个类是一个“组件”,是希望由Spring进行管理的!

以上4个注解中,@Component表示“通用组件类”,@Controller表示“控制器类”,@Service表示“业务类”,@Repository表示“数据访问类/持久层处理的类”,这4个注解只有语义的区别,从功能和用法上来说,是完全一样的!即,如果愿意的话,可以用@Service注解添加在控制器类的声明之前,但是,不推荐这样做。

仅仅只是添加注解是不够的,还需要在Spring的配置文件中开启组件扫描:

<context:component-scan base-package="cn.tedu.spring.dao" />

以上配置中,base-package表示根包,即当配置为cn.tedu.spring时,其子级包例如cn.tedu.spring.daocn.tedu.spring.service等都在扫描范围之内!

如果没有显式的指定bean-id,默认为使用类名且首字母改为小写,例如UserDao类的bean-id就是userDao

以上注解都可以添加配置,例如@Service("bean-id")

小结:通用注解共4个,其功能、用法都是完全相同的,只是表达的语义不同,添加的注解的类,并且在组件扫描范围之内,就会被Spring所管理,在配置组件扫描时,配置的包是“根包”,其范围不宜过大,在添加注解时,还可以自定义bean-id。

2.3. 作用域与生命周期

由Spring管理的对象,默认是饿汉式的单例的,通过在类的声明之前添加注解@Lazy可以调整:

@Component("userDao")
@Lazy(true)
public class UserDao {
}

还可以通过@Scope("singleton")@Scope("prototype")注解调整是否为单例的:

@Service
@Scope("prototype")
public class UserService {
}

关于生命周期方法,依然是先自定义生命周期方法,在初始化方法之前添加@PostConstruct注解,在销毁方法之前添加@PreDestroy注解,这2个注解都是Java EE的注解,来自javax包下,所以,在使用之前,需要为当前项目添加Tomcat运行环境,代码部分例如:

@Component("userDao")
public class UserDao {

    public UserDao() {
        System.out.println("UserDao的构造方法被执行!");
    }

    @PostConstruct
    public void init() {
        System.out.println("UserDao.init()");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("UserDao.destroy()");
    }

}

注意:如果导入他人的项目,或者本机更换了Tomcat软件,都需要重新勾选项目属性中的Targeted Runtimes中的Tomcat。

2.4. 【重要】自动装配

假设在UserDao中存在public void findUserByUsername()方法,然后,在UserService中声明了private UserDao userDao;属性,并且,存在public void login()方法,在方法内部,调用了userDaofindUserByUsername()方法:

@Component("userDao")
public class UserDao {

    public void findUserByUsername() {
        System.out.println("UserDao.findUserByUsername()");
    }

}

@Service
public class UserService {

    private UserDao userDao;

    public void login() {
        System.out.println("UserService.login()");
        userDao.findUserByUsername();
    }

}

在需要自动装配属性值的属性之前,添加@Autowired注解,就可以实现自动装配:

@Autowired
private UserDao userDao;

注意:使用注解的自动装配不需要为属性添加SET方法!

添加@Autowired实现自动装配,其装配方式是byType的,所以,在使用时,需要确保“其对应的值在Spring容器中应该是有且仅有1个的”!

通过@Resource注解也可以实现自动装配!它是优先根据byName实现自动装配,在没有显式的指定bean-id的情况下,如果无法byName装配,则会尝试根据byType实现自动装配。

在实际使用时,可以自由选取以上2个注解中的任何一个!因为,在实际应用中,命名应该是规范的,并且,匹配类型的也应该是有且仅有1个。

以上2个注解中,@Autowired是Spring的环境中的注解类,而@Resource是Java EE环境中的注解类。

QAQ感谢你的支持=w=