8.Spring使用注解实现IoC的配置?实现Bean装配?注解定义切面?

目录


Spring专栏目录(点击进入…)



使用注解实现IoC的配置

从Spring 2.0版本开始引入注解的配置方式,将Bean的配置信息和Bean实现类结合在一起,进一步减少了配置文件(applicationContext.xml)的代码量

注解:以将它理解为将类或者方法与特定的信息进行关联

注解定义Bean

在JavaBean中通过注解实现Bean组件的定义

(1)@Component

表示一个带注释的类是一个“组件”,成为Spring管理的Bean,相当于通用的注解,当不知道一些类归到哪个层时使用,但是不建议使用
当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时@Component还是一个元注解

把普通pojo实例化到Spring容器中

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

与在XML配置文件中等效

<bean id="userDao" class="cn.my.UserDao"/>

(2)@Repository

组合注解(组合了@Component注解),应用在dao层(数据访问层),在daoImpl类上面注解

(3)@Service

组合注解(组合了@Component注解),应用在service层(业务逻辑层),serviceImpl类上注解,标注业务类

(4)@Controller

标注控制器类。无需继承特定的类或实现特定的接口,只需使用@Controller标记一个类是Controller,然后使用@RequestMapping和@RequestParam等一些注解用以定义URL请求和Controller方法之间的映射,这样的Controller就能被外界访问到。此外Controller不会直接依赖于HttpServletRequest和HttpServletResponse等HttpServlet对象,它们可以通过Controller的方法参数灵活的获取到。

@Controller用于标记在一个类上,使用它标记的类就是一个Spring MVC Controller对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是真正处理请求的处理器

单单使用@Controller标记在一个类上还不能真正意义上的说它就是Spring MVC的一个控制器类,因为这个时候Spring还不认识它。那么要如何做Spring才能认识它呢?这个时候就需要把这个控制器类交给Spring管理。

有两种方式:

在Spring MVC的配置文件中定义MyController的bean对象

<bean class="com.my.controller.MyController"/>

在Spring MVC的配置文件中告诉Spring该到哪里去找标记为@Controller 的Controller控制器

<context:component-scan base-package="com.my"/>
//路径写到controller的上一层

实现Bean装配

@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。

(1)@Autowired(byType)

@Autowired顾名思义,就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。

@Autowired采用按类型匹配方式为属性自动装配合适的依赖对象,即容器会查找和属性类型相匹配的Bean组件,并自动为属性注入。若容器中有一个以上类型相匹配的Bean时,则可以使用@Qualifier指定所需的Bean的名称。

@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired。只按照byType注入
下面两种@Autowired只要使用一种即可。

@Autowired
private UserDao userDao; // 用于字段上
private UserDao userDao;

@Autowired
public void setUserDao(UserDao userDao) { // 用于属性的方法上
	   this.userDao = userDao;
}

@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用

@Autowired
@Qualifier("userDao")
private UserDao userDao; 

(2)@Resource(byName/byType)

Spring还支持使用JSR-250中定义的@Resource注解实现组件装配,该标准注解也能对类的成员变量或方法入参提供注入功能。

JSR全称是Java Specification Requests,即Java规范提案。Java的版本和功能在不断地更新和扩展,JSR就是用来规范这些功能和接口的标准,已经成为Java业界的一个重要的标准。

@Resource默认按照byName自动注入,由Java EE提供,需要导入包javax.annotation.Resource。两个重要的属性:name和type
(1)Spring将@Resource注解的name属性解析为bean的名字
(2)type属性则解析为bean的类型

所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略

@Resource有一个name属性,默认情况下,Spring将这个属性的值解释为要注入的Bean的名称
如果没有显式地指定Bean的名称,@Resource注解将根据字段名或者setter方法名产生默认的名称

1.注解应用于字段

将使用字段名作为Bean的名称

@Resource(name="userDao")
private UserDao userDao; // 用于字段上

2.注解应用于setter方法

Bean的名称就是通过setter方法得到的属性名

private UserDao userDao; // 用于字段上

@Resource(name="userDao")
public void setUserDao(UserDao userDao) { // 用于属性的setter方法上
	this.userDao = userDao;
}	

注意:最好是将@Resource放在setter方法上,因为这样更符合面向对象的思想,通过set、get去操作属性,而不是直接去操作属性。

@Resource装配顺序

(1)如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
(2)如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
(3)如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常
(4)如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配
@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入

共同点

两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法


加载注解定义的Bean(包扫描)

首先在Spring配置问价中添加对context命名空间的声明,然后使用context命名空间下的component-scan标签扫描注解标注的类。base-package属性指定了需要扫描的基准包(多个包名可用逗号隔开)。Spring会扫描这些包中所有的类获取Bean的定义信息

<context:component-scan base-package="com.my"/>

注解定义切面

AspectJ是一个面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译器提供代码的织入,所以它有一个专门的编译器用来生成遵守字节编码规范的Class文件。

@AspectJ是AspectJ 5新增的功能,使用JDK注解技术和正规的AspectJ切点表达式语言描述切面。因此在使用@AspectJ之前,需要保证所使用的JDK 5.0及其以上版本,否则无法使用注解技术。

Spring通过继承AspectJ实现了以注解的方式定义切面,大大减少了配置文件的工作量。因为Java的反射机制无法获取方法参数名,Spring还需要利用轻量级的字节码处理框架ASM(已集成在Spring Core模块中)处理@AspectJ中所描述的方法参数名。

注解描述
@Aspect声明一个切面(就是说这是一个额外功能)
@PointCut声明切点,即定义拦截规则,确定有哪些方法会被切入
@Before执行一个业务方法之前插入的切面
@AfterReturning它是当一个方法正常运行后,执行的切面
@After方法执行成功、出现异常的时候都会执行切面
@AfterThrowing如果在方法中有错误抛出,则执行此建议
@Around相当于一个AOP链,如果当前AOP执行后,就让下一个AOP执行

(1)使用注解定义前置增强和后置增强实现日志功能

@Aspect
public class LogAop {
	@Before("execution(public void com.my.dao.impl.StudentDaoImpl.*(..))")
	public void logBefore() {
		System.out.println("方法执行之前转载日志");
	}
}

(2)编写Spring配置文件,完成切面织入

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
注解描述
@Configuration声明当前类是一个配置类(相当于一个Spring配置的xml文件)
@ComponentScan自动扫描指定包下所有使用@Service、@Component、@Controller、@Repository的类并注册
@Bean注解在方法上,声明当前方法的返回值为一个Bean。返回的Bean对应的类中可以定义init()方法和destroy()方法,然后在@Bean(initMethod=”init”,destroyMethod=”destroy”)定义,在构造之后执行init,在销毁之前执行destroy
注解描述
@Value值得注入。经常与Sping EL表达式语言一起使用,注入普通字符,系统属性,表达式运算结果,其他Bean的属性,文件内容,网址请求内容,配置文件属性值等等
@PropertySource指定文件地址。提供了一种方便的、声明性的机制,用于向Spring的环境添加PropertySource。与@Configuration类一起使用

利用Spring的 @PropertySource 和 @Value 两个注解从配置文件properties中读取值,以及如何从配置文件中的值转换为List对象


注解使用实例

1.配置包扫描器、加载配置文件

@Configurable
// 配置包扫描器
@ComponentScan(basePackages = "com.uhhe")
// 加载配置文件
@PropertySource(value = "classpath:spring/config.properties")
public class AppConfigTest {
    
    @Bean
    public PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
        return new PropertySourcesPlaceholderConfigurer();
    }
    
}

通过 @PropertySource 注解将properties配置文件中的值存储到Spring的 Environment 中,Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。上面是读取一个配置文件,如果你想要读取多个配置文件,请看下面代码片段:

@PropertySource(value = {"classpath:spring/config.properties","classpath:spring/news.properties"})

2.config.properties配置文件

server.name=uhhe
server.id=uhhe id
server.host=127.0.0.1

3.Class类中使用属性注入

@Configuration
public class UhheTest {

	@Value("${server.name}")
	private Stiring  servers;
	
	@Value("${server.id}")
	private Stiring  serverId;
	
	@Value("${server.host:127.0.0.1}")
	private Stiring host;
	
}

4.在其他类中注入使用

@Component
public class Account {

    @Autowired
    private UhheTest uhheTest ;

    public void output(){
        System.out.println(uhheTest );
    }

}

非Spring容器管理对象

非Spring管理的对象,这里指的是我们自己new的对象,比如Dog dog = new Dog(),这个dog对象的生命周期不是由Spring管理的,而是我们自己创建的对象,根据文档的说法,我们只要在类上面加上@Configurable注解,就可以让Spring来配置这些非Spring管理的对象了,即为它们注入需要的依赖(实际上还有很多额外的工作要做)。下面有个例子

// Account类,使用new操作符号手动创建,不交由Spring Container管理
@Configurable(autowire = Autowire.BY_TYPE)
public class Account {

    @Autowired
    Dog dog;

    public void output(){
        System.out.println(dog);
    }

}

上面的Account类使用的是@Configurable,而不是@Configuration,@Configuration类似于XML配置里面的<beans></beans>,我们可以在<beans></beans>里面声明要交由Spring Cotainer创建和管理的Bean,因此我们可以在@Configuration注解的类里面使用@Bean注解达到同样的效果,注意被@Configuration标注的类也会被Spring Container创建和管理,因此它也是一个Bean。

被@Configuration标注的类,能够被Spring配置,然后当我们手动创建Account对象的时候(Account acc = new Account()),Spring将会用创建一个Account的Bean,然后这个Bean能被Spring正常地注入需要的属性,接着Spring使用这个Bean来设置我们刚刚创建的

Account对象(acc)的属性,最后返回的对象的属性就和Bean的一样了。

// 配置类,使用注解的方式创建Bean
@Configuration
@EnableLoadTimeWeaving
@EnableSpringConfigured
public class Config {
    // 这个Bean将会被注入到Account的属性中
    @Bean
    Dog dog(){
        Dog d = new Dog();
        d.setId(1);
        d.setName("dog");
        return d;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值