文章40 | 阅读 20109 | 点赞0
还记得在《Spring入门第三讲——Spring中Bean的配置与管理以及分模块开发的配置》这一讲中,我说过Spring进行Bean的管理有两种方式吗?其中一种是使用配置文件的方式,这个我们已经讲过了,还有一种是使用注解的方式,本讲就来讲一下Spring IoC的注解开发。那啥是注解呢?注解是代码中的特殊标记,它可以使用在类、方法、属性上面,使用它可以实现一些基本的功能,其写法是@注解名称(属性=属性值)
。
首先创建一个动态web项目,例如spring_demo02,然后导入Spring框架相关依赖jar包,要导入哪些jar包呢?在Spring4的版本中,除了要导入Spring基本的开发包以外(可参考《Spring入门第一讲——Spring框架的快速入门》这一讲),还须导入Spring注解的jar包。
首先,在src目录下创建一个com.meimeixia.spring.demo01包,并在该包下创建一个名为UserDao的接口。
package com.meimeixia.spring.demo01;
public interface UserDao {
public void save();
}
然后,在com.meimeixia.spring.demo01包下创建UserDao接口的一个实现类——UserDaoImpl.java。
package com.meimeixia.spring.demo01;
/** * 用户Dao的实现类 * @author liayun * */
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl中保存用户的方法执行了......");
}
}
在src目录下面创建Spring的核心配置文件(即applicationContext.xml),由于现在我们使用的是注解方式开发,所以还需要在该配置文件中引入context约束,那么问题来了,这个约束又该怎么写呢?可参考docs\spring-framework-reference\html目录下的xsd-configuration.html文件,在其内容中找到如下内容。
将其复制黏贴到配置文件applicationContext.xml中,这样applicationContext.xml文件的内容就是下面的样子了。
<?xml version="1.0" encoding="UTF-8"?>
<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 http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
咱要想使用IoC的注解开发,还得配置一个组件扫描,就是告诉Spring哪些包下面的哪些类上要使用IoC注解,扫描是为了扫描类上的注解。
在com.meimeixia.spring.demo01包下创建一个SpringDemo01的单元测试类,其内容如下:
package com.meimeixia.spring.demo01;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/** * Spring的IOC的注解开发的测试类 * @author liayun * */
public class SpringDemo01 {
/* * 传统方式 */
@Test
public void demo01() {
UserDao userDao = new UserDaoImpl();
userDao.save();
}
/* * Spring的IOC的注解方式 */
@Test
public void demo02() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
}
然后,运行以上demo02单元测试方法,Eclipse控制台就会打印出如下内容。
该注解是用于修饰一个类,即将这个类交给Spring来管理。这个注解有三个衍生注解(功能类似),同样用于修饰类,它们分别是以下三个注解(推荐使用)。
@Repository
:用于对dao层实现类进行标注(持久层);@Service
:用于对service层实现类进行标注(业务层);@Controller
:用于对Controller实现类进行标注(web层)。我们可以使用@Value这个注解来注入普通属性的值,这里我会举一个例子来演示该注解的使用。现在,如果想要给UserDaoImpl这个实现类里面的某一个属性(例如String类型的name)使用注解方式设置值,那该咋怎呢?使用注解方式来设置属性的值,也有两种方式。
下面,我将UserDaoImpl这个实现类修改成下面这个样子。
package com.meimeixia.spring.demo01;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/** * 用户Dao的实现类 * @author liayun * */
@Component("userDao")//写了这个注解之后,它就相当于在applicationContext.xml里面配置了<bean id="userDao" class="com.meimeixia.spring.demo01.UserDaoImpl" />
public class UserDaoImpl implements UserDao {
//使用注解方式来设置属性的值
@Value("狄仁杰")
private String name;
// @Value("狄仁杰")
// public void setName(String name) {
// this.name = name;
// }
@Override
public void save() {
System.out.println("UserDaoImpl中保存用户的方法执行了......" + name);
}
}
此时,Spring配置文件不用修改,然后运行SpringDemo01单元测试类中demo02方法,你就会看到Eclipse控制台打印出了如下内容。
这里,我会举一个例子来说明如何使用注解方式注入对象类型的属性。首先,在com.meimeixia.spring.demo01包下创建一个名为UserService的接口。
package com.meimeixia.spring.demo01;
public interface UserService {
public void save();
}
然后,在该包下再创建该接口的一个实现类——UserServiceImpl.java。
package com.meimeixia.spring.demo01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("userService")//它相当于在applicationContext.xml里面配置了<bean id="userService" class="com.meimeixia.spring.demo01.UserServiceImpl" />
public class UserServiceImpl implements UserService {
//注入UserDao,此时可以没有set方法
@Autowired
private UserDao userDao;
@Override
public void save() {
System.out.println("UserServiceImpl中的save方法执行了......");
userDao.save();
}
}
从上面可以看到,在UserServiceImpl类里面注入UserDao类的对象时,是使用@Autowired注解来实现的。@Autowired虽说可以设置对象类型的属性的值,但它默认是按照类型来完成属性注入的,咱之前是按照名称来完成属性注入的。
接着,在SpringDemo01的单元测试类中编写如下的一个demo03测试方法。
package com.meimeixia.spring.demo01;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/** * Spring的IOC的注解开发的测试类 * @author liayun * */
public class SpringDemo01 {
/* * 传统方式 */
@Test
public void demo01() {
UserDao userDao = new UserDaoImpl();
userDao.save();
// UserDaoImpl userDao = new UserDaoImpl();
// userDao.setName("李元芳");
// userDao.save();
}
/* * Spring的IOC的注解方式 */
@Test
public void demo02() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
/* * Spring的IOC的注解方式 */
@Test
public void demo03() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.save();
}
}
最后,运行以上demo03单元测试方法,你就会发现Eclipse控制台打印了如下内容。
上面我说过@Autowired虽然可以设置对象类型的属性的值,但是它默认是按照类型来完成属性注入的,而我们习惯是按照名称来完成属性注入,所以还必须让@Autowired这个注解和@Qualifier这个注解一起使用,按照名称来完成属性注入。
@Autowired和@Qualifier这2个注解结合一起使用,它有一个替代的注解(即@Resource),我们在实际的开发中,一般使用这个替代的注解,但这个替代的注解本身不是Spring里面提供的,是Spring实现的一套规范里面提供的。这个替代的注解是@Resource,用它可以完成对象类型的属性注入,而且是按照名称来完成属性注入。
在《Spring入门第三讲——Spring中Bean的配置与管理以及分模块开发的配置》这一讲中,我就已经讲过Bean的生命周期的配置,现在我来用注解的方式再讲一遍。与Bean生命周期相关的注解有以下两个:
@PostConstruct
:用它来标注Bean被初始化的时候执行的方法;@PreDestroy
:用它来标注Bean被销毁的时候执行的方法。下面我会通过一个案例来演示与Bean生命周期相关的这两个注解。首先,在src目录下创建一个com.meimeixia.spring.demo02包,并在该包下创建一个名为CustomerService的类。
package com.meimeixia.spring.demo02;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Service;
@Service("customerService")
//@Scope("prototype")
public class CustomerService {
//<bean id="customerService" class="..." init-method="init" destroy-method="destroy" />
@PostConstruct //相当于我们配置的init-method="init"
public void init() {
System.out.println("CustomerService被初始化了......");
}
public void save() {
System.out.println("CustomerService中的save方法执行了......");
}
@PreDestroy //相当于我们配置的destroy-method="destroy"
public void destroy() {
System.out.println("CustomerService被销毁了......");
}
}
然后,在com.meimeixia.spring.demo02包下创建一个SpringDemo02的单元测试类。
package com.meimeixia.spring.demo02;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringDemo02 {
@Test
public void demo01() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService customerService = (CustomerService) applicationContext.getBean("customerService");
System.out.println(customerService);
applicationContext.close();//此时,CustomerService这个类是被单例创建的,当工厂类被关闭时,被@PreDestroy注解标注的销毁方法就能被执行了。
}
}
接着,还要将以上类交给Spring来管理,所以咱们得告诉Spring扫描com.meimeixia.spring.demo02这个包下面的类。
当然了,我们还可以像下面这样配置,即告诉Spring扫描com.meimeixia.spring.demo01和com.meimeixia.spring.demo02的父包——com.meimeixia.spring。
最后,运行SpringDemo02单元测试类中的demo01方法,你就会看到Eclipse控制台打印出了如下内容。
之前我就说过,要想Bean被销毁的时候执行@PreDestroy注解标注的销毁方法,那么前提Bean得是单例创建的,默认即单例创建,就像下面这样。
如果Bean改为了多例模式创建,就像下面这样。
那么当工厂类被关闭时,@PreDestroy注解标注的销毁方法也就不会被执行了。你可以试着运行一下demo01测试方法,你会发现Eclipse控制台打印出了如下内容。
@Scope
就是与Bean作用范围相关的注解,它的取值咱之前就已经讲过了,这里不再赘述,重点关注singleton和prototype这两个取值。
在我们把CustomerService类交给Spring来管理时,明确该Bean的@Scope注解取值为singleton。
接着,在SpringDemo02的单元测试类中编写如下的一个demo02测试方法。
package com.meimeixia.spring.demo02;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringDemo02 {
@Test
public void demo01() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService customerService = (CustomerService) applicationContext.getBean("customerService");
System.out.println(customerService);
applicationContext.close();//此时,CustomerService这个类是被单例创建的,当工厂类被关闭时,被@PreDestroy注解标注的销毁方法就能被执行了。
}
@Test
public void demo02() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService customerService1 = (CustomerService) applicationContext.getBean("customerService");
System.out.println(customerService1);
CustomerService customerService2 = (CustomerService) applicationContext.getBean("customerService");
System.out.println(customerService2);
applicationContext.close();
}
}
紧接着,运行以上demo02单元测试方法,你就会发现Eclipse控制台打印了如下内容。
验证了Bean默认就是单例创建的。
如果把CustomerService类交给Spring来管理时,明确该Bean的@Scope注解取值为prototype。
那么此时运行以上demo02单元测试方法,你就会发现Eclipse控制台打印了如下内容。
从上图中,我们就能看出Bean现在是多例模式创建的了。而且工厂类关闭之后,它也没被销毁,因为现在内存里面是有很多个对象,它不知道要销毁哪一个具体的CustomerService类的对象,所以,要想工厂类被关闭之后,Bean被销毁(此时将会执行@PreDestroy注解标注的销毁方法),那么Bean得是单例创建的(默认即单例创建)!
这里,我会对IoC的XML开发方式和注解开发方式做一个简单的比较。
有时候,这两种方式都会使用,即XML文件和注解的整合开发,在这种整合开发中,我们会使用XML文件来管理Bean,使用注解完成属性注入。下面我会通过一个案例来演示XML文件和注解的整合开发。
首先,在src目录下创建一个com.meimeixia.spring.demo03包,并在该包下创建一个名为OrderDao的类和一个名为ProductDao的类。
package com.meimeixia.spring.demo03;
public class OrderDao {
public void save() {
System.out.println("OrderDao中的save方法执行了......");
}
}
package com.meimeixia.spring.demo03;
public class ProductDao {
public void save() {
System.out.println("ProductDao中的save方法执行了......");
}
}
然后,在com.meimeixia.spring.demo03包下创建一个ProductService类。
package com.meimeixia.spring.demo03;
import javax.annotation.Resource;
public class ProductService {
@Resource(name="productDao")
private ProductDao productDao;
@Resource(name="orderDao")
private OrderDao orderDao;
// public void setProductDao(ProductDao productDao) {
// this.productDao = productDao;
// }
// public void setOrderDao(OrderDao orderDao) {
// this.orderDao = orderDao;
// }
public void save() {
System.out.println("ProductService中的save方法执行了......");
productDao.save();
orderDao.save();
}
}
从以上ProductService类的代码中,我们可以看到使用注解完成了属性注入。
接着,咱要将以上三个类交给Spring来管理,即使用XML文件来管理Bean。现在,我们只是运行com.meimeixia.spring.demo03包下的类,所以咱可以不用开启组件扫描,组件扫描是为了扫描类上的注解,但我们现在的类上是没有注解的,那么咱必须得开启另外一个东西,即<context:annotation-config />
。一旦你在Spring配置文件里面写了这个东西,那么这时就可以在没有组件扫描的情况下,来使用那些属性注入的注解,也就是说可以直接使用@Resource、@Value、@Autowired、@Qualifier这些注解了。
<?xml version="1.0" encoding="UTF-8"?>
<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 http://www.springframework.org/schema/context/spring-context.xsd">
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~Spring的IOC的注解的入门~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- 其实我们只运行com.meimeixia.spring.demo03包下的类的话,可以不用扫描,但是你得开个别的东西。 扫描是为了扫描类上的注解,但我们现在的类上是没有注解的。 那么你现在到这里面必须得开启另外一个东西。 <context:annotation-config />:这时可以在没有扫描的情况下,来使用那些属性注入的注解。也即可以直接使用@Resource、@Value、@Autowired、@Qualifier这些注解。 -->
<context:annotation-config />
<bean id="productService" class="com.meimeixia.spring.demo03.ProductService">
<!-- <property name="productDao" ref="productDao" /> <property name="orderDao" ref="orderDao" /> -->
</bean>
<bean id="productDao" class="com.meimeixia.spring.demo03.ProductDao"></bean>
<bean id="orderDao" class="com.meimeixia.spring.demo03.OrderDao"></bean>
</beans>
紧接着,在com.meimeixia.spring.demo03包下创建一个SpringDemo03的单元测试类,其内容如下:
package com.meimeixia.spring.demo03;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/** * XML文件和注解的整合开发 * @author liayun * */
public class SpringDemo03 {
@Test
public void demo01() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ProductService productService = (ProductService) applicationContext.getBean("productService");
productService.save();
}
}
最后,运行以上demo01单元测试方法,Eclipse控制台就会打印出如下内容。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://liayun.blog.csdn.net/article/details/100511171
内容来源于网络,如有侵权,请联系作者删除!