首页 > Spring 实践 -IoC

Spring 实践 -IoC

Spring 实践

标签: Java与设计模式


Spring简介

Spring是分层的JavaSE/EE Full-Stack轻量级开源框架.以IoC(Inverse of Control 控制反转)和AOP(Aspect Oriented Programming 面向切面编程)为内核, 取代EJB的臃肿/低效/脱离现实.

主页http://spring.io/

此处输入图片的描述

IoC与DI

  • IOC: 即控制反转, 解决程序对象紧密耦合问题(方式: 工厂+反射+配置文件), 将程序中原来构造对象的操作,交给IoC容器, 当程序真正需要对象时,再找IoC容器获取.

  • DI: 即依赖注入, IoC容器需要为程序提供依赖对象,而所依赖的对象又依赖于其他对象,因此可以一次获取该对象所依赖的所有对象(如Controller依赖于Service, Service依赖于DAO, 因此Controller找Ioc容器获取Service, 当IoC容器提供Service的同时,DAO也同时注入到Service中)



    详细可参考: IoC框架(依赖注入 DI)

Spring

  • 方便解耦,简化开发

    Spring就是一个大工厂,可将所有对象创建依赖关系的维护交给Spring管理;
  • AOP支持

    Spring支持面向切面编程,可以方便的实现对程序进行权限拦截/运行监控/缓存实现等功能;
  • 声明式事务管理

    只需通过配置就可完成对事务的管理,而无需手动编程;
  • 方便程序的测试

    Spring提供对Junit4支持,通过注解方便测试Spring程序;
  • 集成各种优秀框架

    Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:MyBatis/iBatis/Hibernate等)的直接支持;
  • 降低JavaEE API的使用难度

    Spring对JavaEE开发的一些API(如JDBC/JavaMail/远程调用等)提供了封装,大大降低API使用难度;

初识Spring

需求- 模拟用户注册过程:

  • Spring依赖

    进行Spring的IoC/DI开发,只需要导入Spring最核心依赖:core/beans/context/expression,为了看到DEBUG信息,我们还可以加上commons-logging, 而junit, 则是做单元测试必备的:
<dependencies><dependency><groupId>org.springframeworkgroupId><artifactId>spring-coreartifactId><version>4.2.0.RELEASEversion>dependency><dependency><groupId>org.springframeworkgroupId><artifactId>spring-contextartifactId><version>4.2.0.RELEASEversion>dependency><dependency><groupId>org.springframeworkgroupId><artifactId>spring-beansartifactId><version>4.2.0.RELEASEversion>dependency><dependency><groupId>org.springframeworkgroupId><artifactId>spring-expressionartifactId><version>4.2.0.RELEASEversion>dependency><dependency><groupId>commons-logginggroupId><artifactId>commons-loggingartifactId><version>1.2version>dependency><dependency><groupId>junitgroupId><artifactId>junitartifactId><version>4.11version>dependency>
dependencies>
  • Controller
/*** Created by jifang on 15/12/5.*/
public class UserController { /*** 依赖注入(DI): 在Spring构造UserController对象时, 可以同时将构造好的UserService对象注入(下同)*/private IUserService userService;public IUserService getUserService() {return userService;}public void setUserService(IUserService userService) {this.userService = userService;}public void register(String userName, String password) {System.out.println("用户: " + userName + " 进行注册...");userService.register(userName, password);}
}
  • Service
public interface IUserService {void register(String userName, String password);
}
public class UserServiceImpl implements IUserService { private IUserDao userDao;public IUserDao getUserDao() {return userDao;}public void setUserDao(IUserDao userDao) {this.userDao = userDao;}@Overridepublic void register(String userName, String password) {System.out.println("用户: " + userName + " 进行注册...");userDao.add(userName, passProcess(password));}// 对密码进行加密处理private String passProcess(String password) {System.out.println("密码: " + password + "加密处理...");return password;}
}
  • DAO
public interface IUserDao {void add(String userName, String password);
}
public class UserDaoImpl implements IUserDao { @Overridepublic void add(String userName, String password) {System.out.println("用户: " + userName + ", 密码: " + password + " 加入数据库");}
}
  • 配置Bean

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userDao" class="com.fq.first.dao.impl.UserDaoImpl">bean><bean id="userService" class="com.fq.first.service.impl.UserServiceImpl"><property name="userDao" ref="userDao">property>bean><bean id="userController" class="com.fq.first.controller.UserController"><property name="userService" ref="userService">property>bean>beans>
  • 测试
/*** Created by jifang on 15/12/5.*/
public class UserControllerTest extends TestCase { /*** 加载Spring容器*/private ApplicationContext context;@Beforepublic void setUp() throws Exception {context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");}@Testpublic void testRegister() throws Exception {UserController controller = context.getBean("userController", UserController.class);controller.register("翡青", "123");}
}
  1. 在程序中通过ApplicationContext接口加载Spring容器, 获取Spring工厂对象

    • ClassPathXmlApplicationContext //读取src下配置文件
    • FileSystemXmlApplicationContext //读取WEB-INF下配置文件
  2. Spring对象工厂- BeanFactory与ApplicationContext:

    • ApplicationContextBeanFactory的子接口,BeanFactory是Spring最核心工厂接口。
    • ApplicationContext提供更多功能(如国际化处理/自动装配Bean/不同应用层的Context实现)
    • ApplicationContext会在容器初始化时对其中管理Bean对象进行创建,BeanFactory会在对象获取时才进行初始化.

XML装配

Spring提供了两种装配Bean的方式, XML与注解,其中XML方式Spring支持较早,现在在配置一些不是自己写的Bean时(如数据库连接池等从Jar包种引入的Bean)时是非常有用,而注解方式则常用于装配自己写的Bean.


三种实例化Bean的方式

  • 构造器实例化

<bean id="constructBean" class="com.fq.instance.ConstructBean">
bean>
  • 静态工厂的静态方法实例化

<bean id="staticBean" class="com.fq.instance.StaticBeanFactory" factory-method="getInstance">
bean>
  • 实例工厂的实例方法实例化

<bean id="beanFactory" class="com.fq.instance.InstanceBeanFactory">
bean>

<bean id="instanceBean" factory-bean="beanFactory" factory-method="getInstance">
bean>

Bean作用域

类别说明
singleton在容器中仅存在一个实例(单例模式)
prototype每次从容器中获取都返回一个新的实例,即每次调用getBean()时,都执行一次构造方法(lazy,原型模式)
request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境(不常用)
session同一个Session共享一个Bean,仅适用于WebApplicationContext环境(不常用)
globalSession一般用于Porlet应用环境,该作用域仅适用于WebApplicationContext环境(不常用)
  • scope

<bean id="singletonBean" class="com.fq.instance.SingletonBean" scope="singleton">
bean>
<bean id="prototypeBean" class="com.fq.instance.PrototypeBean" scope="prototype">
bean>

Bean生命周期

Spring初始化/销毁bean时, 有时需要作一些处理工作, 因此Spring可以在创建和销毁bean的时候调用bean的两个生命周期方法;

/*** Created by jifang on 15/12/6.*/
public class LifecycleBean { public LifecycleBean() {System.out.println("Constructor ...");}/*** 声明周期方法需: 无参, 无返回值, 非static*/public void setUp() {System.out.println("SetUp ...");}/*** 同上*/public void tearDown() {System.out.println("TearDown ...");}
}
  • 配置:

<bean id="lifecycleBean" class="com.fq.bean.LifecycleBean" init-method="setUp" destroy-method="tearDown">
bean>
  • 测试
/*** Created by jifang on 15/12/6.*/
public class LifecycleBeanTest extends TestCase { private ClassPathXmlApplicationContext context;@Beforepublic void setUp() throws Exception {context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");}@Testpublic void testLifecycle(){LifecycleBean bean = context.getBean("lifecycleBean", LifecycleBean.class);System.out.println(bean);}@Afterpublic void tearDown() throws Exception {// 必须手动调用context的close方法, 才会执行bean的销毁方法context.close();}
}

初始化方法与构造方法的区别?

1) 构造方法为对象申请空间, 完成对象基本属性的初始化;

2) 初始化方法主要完成对象复杂构造过程;

3) Java建议将对象复杂构造过程单独抽取出初始化方法, 如javax.servlet.GenericServlet

init方法

public void init(ServletConfig config) throws ServletException {this.config = config;this.init();
}

后处理器

Spring提供了BeanPostProcessor接口,在构造Bean对象执行对象初始化(init-method)方法时可以对Bean进行处理;

/*** Created by jifang on 15/12/6.*/
public class PrintBeanProcessor implements BeanPostProcessor { @Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 可以根据beanName来决定对那个Bean进行后处理操作if (beanName.equals("lifecycleBean")) {System.out.println("后处理bean -- process before ...");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 如果不制定beanName, 则默认处理所有BeanSystem.out.println("后处理bean -- process after ...");return bean;}
}
  • 配置

<bean class="com.fq.processor.PrintBeanProcessor">bean>

这样在执行init-method[setUp]的前后, 会分别执行BeanPostProcessor中的两个方法.

后处理器可以在对象构造过程中提供代理,这是AOP自动代理的核心.


XML依赖注入

Spring配置文件支持构造参数属性注入和Setter方法属性注入;

1. 构造参数注入

<bean id="bean" class="com.fq.di.Bean"><constructor-arg index="0" type="java.lang.String" value="fei_qing">constructor-arg><constructor-arg index="1" type="java.lang.Double" value="3.14">constructor-arg>
bean>

2. Setter方法注入

<bean id="bean" class="com.fq.di.Bean"><property name="name" value="fei_qing">property><property name="price" value="88.8">property>
bean>

3. p名称空间注入

P名称空间在spring2.5版本后引入, 目的是为了简化属性依赖注入(setter方法)


<bean id="bean" class="com.fq.di.Bean" p:name="feiqing" p:price="1188">
bean>

4. SpEL表达式

在spring3.0之后,引入SpEL表达式,以简化属性注入.

#{表达式}, 通过value属性注入: 可以引用一个Bean对象/对象属性/对象方法… 详细可参考Spring 表达式语言(SpEL)

  • Bean
public class Car {private String logo;private double price;private String owner;public String getLogo() {return logo;}public void setLogo(String logo) {this.logo = logo;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public String getOwner() {return owner;}public void setOwner(String owner) {this.owner = owner;}
}
public class Employ {private String name;private Car car;public String getName() {return name;}public void setName(String name) {this.name = name;}public Car getCar() {return car;}public void setCar(Car car) {this.car = car;}
}
  • 配置

<bean id="car" class="com.fq.di.Car"><property name="logo" value="#{'logo.pic'}"/><property name="price" value="#{18.8}"/><property name="owner" value="#{'feiqing'}"/>
bean><bean id="employ" class="com.fq.di.Employ"><property name="car" value="#{car}"/><property name="name" value="#{car.getOwner().toUpperCase()}"/>
bean>

4. 集合属性注入

java常见集合: List/Set/Map/Properties等, Spring为每种集合都提供一个标签进行注入;

  • Bean
public class CollectionBean {private List<String> list;private Set<String> set;private Map<String, String> map;private Properties properties;public List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}public Set<String> getSet() {return set;}public void setSet(Set<String> set) {this.set = set;}public Map<String, String> getMap() {return map;}public void setMap(Map<String, String> map) {this.map = map;}public Properties getProperties() {return properties;}public void setProperties(Properties properties) {this.properties = properties;}
}
  • 配置
<bean id="collectionBean" class="com.fq.di.CollectionBean"><property name="list"><list><value>aavalue><value>bbvalue><value>ccvalue><value>ddvalue>list>property><property name="set"><set><value>11value><value>12value><value>11value>set>property><property name="map"><map><entry key="key1" value="value1"/><entry key="key2" value="value2"/>map>property><property name="properties"><props><prop key="key1">value_1prop><prop key="key2">value_2prop>props>property>
bean>

注解装配

注解配置Bean

  • 在需要Spring管理的类上添加@Component注解

    (@Component还可以指定组件名@Component(value = "xxx"))
@Component
public class Bean {private String name;private Double price;public Bean() {}public Bean(String name, Double price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}
}
  • 引入context命名空间并批量扫描

<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"><context:component-scan base-package="com.fq.di"/>
beans>

Spring细化@Component以细分组件功能,提供了以下三个等价注解:

注解说明
@Controller控制器,web层组件
@Service业务类,业务层组件
@Repository持久层组件

Bean作用域

通过@Scope注解指定作用域

@Component
@Scope("prototype")
public class Bean {// ...
}

Bean生命周期

@PostConstruct初始化
@PreDestroy销毁
  • Bean
public class Bean {@PostConstructpublic void setUp(){System.out.println("setUp ...");}@PreDestroypublic void tearDown(){System.out.println("tearDown ...");}
}

注解依赖注入

1. @Value

  • 简单类型
@Component
public class Bean { @Value("feiqing")private String name;@Value("88.88")private Double price;// ....
}
  • 复杂属性(使用SpEL表达式)
@Component
public class Bean {@Value("#{car}")private Car car;// ...
}

2. @Autowired

  • @Autowired 默认按照类型进行注入(如果容器中存在两个相同类型对象,则@Autowired无法注入)
@Component
public class Bean { @Autowiredprivate Car car;// ....
}
  • @Autowired+@Qualifier指定注入Bean的id
@Component
public class Bean { @Autowired@Qualifier("car")private Car car;// ...
}

3. @Resource

Spring支持JSR-250规范,可以使用@Resource()进行属性注入,功能和@Autowired相同:

@Controller(value = "bean")
public class Bean {@Resource(name = "car")private Car car;//...
}

注解/XML混合

Bean定义使用XML,Bean关系依赖注入使用注解:

需要在applicationContext.xml中配置:

<context:annotation-config/>

该配置可以使@Resource@PostConstruct@PreDestroy@Autowired注解生效.

如果在配置文件中使用了则具有了的效果, 不必再单独配置.


转载于:https://www.cnblogs.com/itrena/p/5926901.html

更多相关:

  • 本文参考自: https://blog.csdn.net/ryelqy/article/details/77453713   @Value能让我们在java代码中使用property文件的属性,使用@Value有两种形式: 1、@Value("#{configProperties['t1.msgname']}") 2、@Value("...

  • 本地的activemq的地址: http://localhost:8161/admin/ win10的启动avtivemq E:Program FilesActiveMQapache-activemq-5.15.3inwin64 win64里面的activemq.bat   消息队列的学习 学习地址2 这是spri...

  • 在.Net Framework中,配置文件一般采用的是XML格式的,.NET Framework提供了专门的ConfigurationManager来读取配置文件的内容,.net core中推荐使用json格式的配置文件,那么在.net core中该如何读取json文件呢?1、在Startup类中读取json配置文件1、使用Confi...

  •   1 public class FrameSubject extends JFrame {   2    3   …………..   4    5   //因为无法使用多重继承,这儿就只能使用对象组合的方式来引入一个   6    7   //java.util.Observerable对象了。   8    9   DateSub...

  • 本案例主要说明如何使用NSwag 工具使用桌面工具快速生成c# 客户端代码、快速的访问Web Api。 NSwagStudio 下载地址 比较强大、可以生成TypeScript、WebApi Controller、CSharp Client  1、运行WebApi项目  URL http://yourserver/swagger 然后...

  •   在绑定完Action的所有参数后,WebAPI并不会马上执行该方法,而要对参数进行验证,以保证输入的合法性.   ModelState 在ApiController中一个ModelState属性用来获取参数验证结果.   public abstract class ApiController : IHttpController,...

  • 1# 引用  C:AVEVAMarineOH12.1.SP4Aveva.ApplicationFramework.dll C:AVEVAMarineOH12.1.SP4Aveva.ApplicationFramework.Presentation.dll 2# 引用命名空间, using Aveva.Applicati...

  • importjava.security.SecureRandom;importjavax.crypto.Cipher;importjavax.crypto.SecretKey;importjavax.crypto.SecretKeyFactory;importjavax.crypto.spec.DESKeySpec;//结果与DES算...

  • 题目:替换空格 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 输入:s = "We are happy." 输出:"We%20are%20happy." 限制: 0 <= s 的长度 <= 10000 解题: 时间复杂度:O(n) 空间复杂度:O(n) class Solution { public:s...

  • 在C++11标准库中,string.h已经添加了to_string方法,方便从其他类型(如整形)快速转换成字面值。 例如: for (size_t i = 0; i < texArrSize; i++)RTX_Shader.SetInt(string("TexArr[") + to_string(i) + "]", 7 + i);...

  • Ubuntu 14.04安装并升级之后,变成楷体字体非常难看,我昨天搞了一晚上,终于理了个头绪,这里整理一下。 经过网上调研,大家的一致看法是,使用开源字体库文泉驿的微黑字体效果比较理想,甚至效果不输windows平台的雅黑字体。下面我打算微黑来美化Ubuntu 14.04. 1.安装文泉驿微黑字体库 sudo aptitude...

  • 使用string时发现了一些坑。 我们知道stl 容器并不是线程安全的,所以在使用它们的过程中往往需要一些同步机制来保证并发场景下的同步更新。 应该踩的坑还是一个不拉的踩了进去,所以还是记录一下吧。 string作为一个容器,随着我们的append 或者 针对string的+ 操作都会让string内部的数据域动态增加,而动态增加的...