Java框架学习:SpringIoC之使用注解作为配置文件

加载注解解析器组件

使用注解作为配置文件是Spring2.5提供的功能,在Spring3中提供了纯java配置的方式
如果要使用注解,必须加载注解解析器组件,让Spring容器解析注解
注解本身毫无意义,是注解解析器通过反射使之有了意义

在applicationContext.xml配置文件中加载注解解析器组件,使用注解会简化配置文件,但无法脱离配置文件,因为初始化Spring容器时,会读取配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	<!--加载注解解析器组件-->
	<!--告知Spring扫描包,并对注解进行解析,Spring会扫描当前包以及子包-->
    <context:component-scan base-package="com.xupt"/>
</beans>

将bean交给Spring容器

在Spring中存在4个注解可将bean交给Spring容器,4个注解本质上是一样的

@Component:用于组件类的bean,即不属于以下三个中的任何一个,就使用该注解
@Service:用于业务逻辑,即Service层中的类
@Repository:用于数据库访问层,即DAO层中的类
@Controller:用于控制层,即Servlet,SpringMVC时使用

将这些注解标注在类上就可以将该类bean交给Spring容器

AccountDaoDB类

import org.springframework.stereotype.Repository;

//通过value属性设置该bean对象的beanid
@Repository("accountDaoDB")
public class AccountDaoDB implements IAccountDao {
    @Override
    public void save(String name) {
        System.out.println("AccountDaoDB save method"+name);
    }
}

AccountService类

import com.xupt.dao.IAccountDao;
import org.springframework.stereotype.Service;

@Service
public class AccountService implements IAccountService {
    private IAccountDao accountDao;
    public void register(String name) {
        accountDao.save(name);
    }
}

此时运行测试类,可以从Spring容器中取出托管的bean对象,但是还不能调用AccountService类的register方法,会报空指针异常。因为还没用注入成员变量accountDao。
测试类

import com.xupt.dao.AccountDao;
import com.xupt.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIOC {
    @Test
    public void testAnnotation(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService=context.getBean("accountService",AccountService.class);
        System.out.println(accountService);
        AccountDao accountDao = context.getBean("accountDao", AccountDao.class);
        System.out.println(accountDao);
    }
}
说明
1.以上4个注解均只能标注类
2.使用以上4个注解交给Spring容器的bean的beanid默认按照类名的驼峰命名法,但也可以通过value属性指定beanid
3.以上4个注解用法相同,不强制限制标注对应的类,但语义不同,在不同的层次中使用对应注解标注类

注入对象

Spring中提供了两个注入对象的注解
@Autowired:使用最多,按照类型注入对象,相当于autowire属性的值byType
	可标注CONSTRUCTOR、METHOD、PARAMETER、FIELD、ANNOTATION_TYPE
	当Spring容器中该类型对象存在两个及两个以上时,会报错。可以结合@Qualifier注解按照名称注入
@Qualifier:与@Autowired注解结合按照名称(beanid)注入对象
	可标注FIELD、METHOD、PARAMETER、TYPE、ANNOTATION_TYPE
	该注解不能单独使用,否则会出现异常,必须结合@Autowired注解
	
JavaEE规范中的注入对象注解,需要导入javax.annotation的jar包
@Resource:可以按照类型也可以按照名称注入对象,默认按照名称
	可标注TYPE,、FIELD,、METHOD
	通过设置name属性指定注入对象beanid;通过设置type属性来指定注入对象的类型	

@Autowired、@Qualifier注解的使用示例

import com.xupt.dao.IAccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class AccountService implements IAccountService {
    @Autowired
    //通过该注解设置注入对象的beanid
    @Qualifier("accountDaoDB")
    private IAccountDao accountDao;
    public void register(String name) {
        accountDao.save(name);
    }
}

@Resource注解的使用示例

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class AccountService implements IAccountService {
	//默认按照类型注入对象,通过成员变量的类型来寻找bean
    @Resource
    private IAccountDao accountDao;
    
    public void register(String name) {
        accountDao.save(name);
    }
}
//设置name属性指定注入对象的beanid
@Resource(name="accountDaoDB")
//设置type属性指定注入的类型,type属性的值为字节码文件对象
@Resource(type=AccountDaoDB.class)

使用注解标注成员变量时,是会打破Java的封装性的,因为成员变量是私有的,不允许在类的外部被直接访问,而注解通过反射直接访问成员变量,为成员变量注入了对象。

Spring中可以通过@Value注解将外部的值动态注入到Bean中
resources目录下存在配置文件db.properties

username=abc
password=123

首先需要在Spring容器中加载该配置文件

<context:property-placeholder location="db.properties"/>

BeanService类

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class BeanService {
	//可以直接赋值,但是这样没有意义,相当于private String username="abc";
    //@Value("abc")
    @Value("${username}")
    private String username;

    public String getUsername() {
        return username;
    }
}

在测试类中获取该类bean对象,并调用getUsername方法

import com.xupt.service.BeanService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIOC {
    @Test
    public void testAnnotation(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanService beanService=context.getBean("beanService", BeanService.class);
        /*输出的值与配置文件中的值不符
        因为Spring中存在一个配置文件,文件中也存在键username
        如果注入配置文件中的password对应的值输出后无异常*/        
        System.out.println(beanService.getUsername());
    }
}

为了避免多个配置文件中存在名称一样的键,可以也命名键名时加上文件前缀,因为文件名称是唯一的,如下:

db.username=abc
db.password=123

作用域、初始化、销毁

@Scope:用于指定bean对象的作用域,默认为singleton
	可标注TYPE、METHOD,一般标注TYPE
	该注解的两个属性scopeName和value互为别名,即设置其中一个属性的值,另一个属性自动被设置为同样的值
@PostConstruct:用于标注初始化方法
@PreDestroy:用于标注销毁方法	

@Scope注解由Spring提供,@PostConstruct和@PreDestroy注解由JavaEE提供,且只能标注METHOD
import com.xupt.dao.IAccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Service
//将作用域设置为原型模式,一般bean对象的作用域都设置为单例模式
//原型模式的使用,比如一个类用于获取Connection,每次都需要获取一个新的Connection对象。
@Scope("prototype")
public class AccountService implements IAccountService {
    @Autowired
    @Qualifier("accountDaoDB")
    private IAccountDao accountDao;

    public void register(String name) {
        accountDao.save(name);
    }

	//标注初始化方法
    @PostConstruct
    public void init(){
        System.out.println("init...");
    }

	//标注销毁方法
    @PreDestroy
    public void destroy(){
        System.out.println("destroy...");
    }
}

探究@Scope注解中互为别称的属性
@Scope注解的代码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
    @AliasFor("scopeName")
    String value() default "";

    @AliasFor("value")
    String scopeName() default "";

    ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
@AliasFor:用于标注自定义注解的两个属性,使这两个属性互为别名
	互为别名的属性属性值类型、默认值都是相同的,互为别名的注解必须成对出现,且必须定义默认值	

Spring3中纯Java配置方式

纯Java配置方式将不再使用xml配置文件

@Configuration:用于标注类,被标注的类成为配置类,可替换xml配置文件
@ComponentScan:用于标注配置类,定义扫描的路径,相当于<context:component-scan>标签
@PropertySource:用于标注配置类,加载指定的属性配置文件,默认从classes目录下寻找,相当于<context:property-placeholder>标签
@Bean:用于标注配置类中的方法,将方法的返回值存放在Spring容器中,默认的beanid为方法的名称
	如果程序中引用了第三方的类,需要将该类对象交给Spring容器,但是不能修改类的源代码,就需要使用@Bean注解

在config包下创建ApplicationConfig类作为配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.util.Date;

@Configuration
@ComponentScan("com.xupt")
@PropertySource("db.properties")
public class ApplicationConfig {
	//bean对象的beanid默认为方法名,即"createDate",可以通过value值指定beanid
    @Bean("springIocDate")
    public Date createDate(){
        return new Date();
    }
}

测试类

import com.xupt.config.ApplicationConfig;
import com.xupt.service.AccountService;
import com.xupt.service.BeanService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestIOC {
    @Test
    public void testAnnotation(){
        //AnnotationConfigApplicationContext容器用于解析被@Configuration标注的类,可通过反射获取标注该类的注解
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        
        AccountService accountService=context.getBean("accountService",AccountService.class);
        accountService.register("java");
        
        BeanService beanService=context.getBean("beanService",BeanService.class);
        System.out.println(beanService.getUsername());
        
        Date date = context.getBean("springIocDate", Date.class);
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
    }
}
xml配置文件和注解配置方式的比较
xml配置文件
优点
1.降低耦合,配置与代码相分离,使容易扩展
2.对象之间的关系清晰
3.xml配置文件比注解功能齐全
缺点
配置文件配置工作量较大

注解配置方式
优点
1.在.class文件中,可以降低维护成本
2.提高开发效率
缺点
1.如果对注解进行修改,需要重新编译整个工程
2.业务类之间的关系不如XML配置那样清晰
3.程序中过多的注解对于代码的简洁度有一定影响
4.注解功能没有xml配置文件齐全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值