Java配置是Spring4.x推荐的配置方式,可以完全替代xml配置。
通过两个注解@Configuration和@Bean来实现。
1、@Configuration作用于类上,可以理解为一个xml配置文件。
2、@Bean作用于方法上,可以理解为xml配置中的<bean>。
@Configuration @ComponentScan("com.xw.test") public class SpringConfig { @Bean public UserDao getUserDao() { return new UserDaoImpl(); } }
@Bean注解会自动把方法的名字设置为bean的名字,如上面的就会设置为getUserDao
public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserDao userDao1 = (UserDao) context.getBean("getUserDao"); System.out.println(userDao1); context.destroy(); }
@ComponentScan("com.xw.test")的作用:扫描包
在使用注解的方式时,必须配置
<context:annotation-config/>
作用:向 Spring 容器注册这 4 个BeanPostProcessor
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
使用@Autowired注解,就必须事先在Spring容器中声明AutowiredAnnotationBeanPostProcessor。
使用@Resource 、@PostConstruct、@PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor。
使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor。
使用@Required的注解,就必须声明RequiredAnnotationBeanPostProcessor。
但是:<context:component-scan base-package=XX.XX/>包含了自动注入上述processor的功能。所以就不用写了。
@Autowired和@Resource的区别:
使用@Autowired时,先在容器中查询类型的bean(byType)
1、如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据。
2、如果查询的结果不止一个,那么@Autowired会根据名称来查找。
名称:是指的如下userDao这个名称,或者自己通过注解@Qualifier("getUserDao")来指定名称查找。
@Autowired private UserDao userDao;
3、如果根据名称查询的结果为空,那么会抛出异常。解决方法时,使用required=false。
所以在使用的时候我们一般是在实现类中加@Service、@Repository,名字是默认的,如
@Repository public class UserDaoImpl implements UserDao如上面这种,名称就是类首字母小写userDaoImpl。
注意:像上面的例子,如果有多个实现类UserDaoImpl UserDaoImpl2,根据上面@Autowired的规则,根据类型查找的结果不止一个,且根据名称userDao来查找肯定也不匹配(一个是userDaoImpl,一个是userDaoImpl2),此时就像上面第三步一样,抛出异常,注入失败。此时就可以用@Qualifier("userDaoImpl")来区分。
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.xw.test.UserDao' available: expected single matching bean but found 2: userDaoImpl,userDaoImpl2
使用@Resource时,是根据名字来查找,如下:
@Resource private UserDao userDao;
1、先查找是否有名称为userDao的bean。
2、如果没有找到,则看是否有name属性(@Resource name=“”),有则根据name查找。3、如果还没有找到,则根据类型来查找,如果没有找到或者找到多个则抛出异常。
疑惑:
第一种情况:一个在类上@Repository,一个在标有@Configuration类的方法上。
@Repository("userDaoImpl") public class UserDaoImpl implements UserDao {
@Bean("userDaoImpl") public UserDao getUserDao2() { return new UserDaoImpl2(); }
信息: Overriding bean definition for bean 'userDaoImpl' with a different definition: replacing [Generic bean: class [com.xw.test.UserDaoImpl];
这样是可以共存的,会有个如上Overriding的提示而已。
第二种情况:两个都在类上@Repository
@Repository("userDaoImpl") public class UserDaoImpl implements UserDao {
@Repository("userDaoImpl") public class UserDaoImpl2 implements UserDao {
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.xw.test.SpringConfig]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'userDaoImpl' for bean class [com.xw.test.UserDaoImpl2] conflicts with existing, non-compatible bean definition of same name and class [com.xw.test.UserDaoImpl]此时初始化报错。
两种情况都是注入两个名字一样的不同属于不同类的实例对象,但结果不一样。猜测:和@Configuration有关,有时间再看下源码。
读取外部参数:通过注解@PropertySource("classpath:test.properties")读取指定的配置。
使用参数:
常用的方式一:通过@Value
@Value("${name}") private String name; @Value("${age}") private String age;
常用的方式二:通过Environment
@Autowired private Environment enviroment;enviroment.getProperty("name")即可获取。 借此温习记录下spring的注解。