spring(1)(用spring控制创建对象的细节,创建和注入的方式)
回顾:Struts与Hibernate可以做什么事?
Struts,
Mvc中控制层解决方案
可以进行请求数据自动封装、类型转换、文件上传、效验…
Hibernate,
持久层的解决方案;
可以做到,把对象保存到数据库,从数据库中取出的是对象。
Spring框架
传统的方式,对象创建都是写死的。关于对象创建细节:
1.对象数量:单例,多个
2.创建时间:
action 访问时候创建
service 启动时候创建
dao 启动时候创建
3.对象的依赖关系:service依赖 dao
spring简单来说,就是处理对象的创建的、以及对象的依赖关系!
组件/框架设计
侵入式设计:
引入了框架,对现有的类的结构有影响;即需要实现或继承某些特定类。
例如:Struts框架
非侵入式设计:
引入了框架,对现有的类结构没有影响。
例如:Hibernate框架 / Spring框架
Inversion on Control , 控制反转 IOC
对象的创建交给外部容器完成,这个就做控制反转.(一个类需要一个对象,不在本类中创建)
依赖注入, dependency injection
处理对象的依赖关系(一个类需要一个对象,拿过来的过程)
IOC/DI区别:
控制反转,解决对象创建的问题 【对象创建交给别人】
依赖注入,在创建完对象后, 对象的关系的处理就是依赖注入 【通过set方法依赖注入】
AOP
面向切面编程,切面举例:事务、日志、权限;
Spring框架:
可以解决对象创建以及对象之间依赖关系的一种框架。
且可以和其他框架一起使用;Spring与Struts, Spring与hibernate
(起到整合(粘合)作用的一个框架)
Spring提供了一站式解决方案:
1) Spring Core spring的核心功能: IOC容器, 解决对象创建及依赖关系 2) Spring Web Spring对web模块的支持。 可以与struts整合,让struts的action创建交给spring spring mvc模式 3) Spring DAO Spring 对jdbc操作的支持 【JdbcTemplate模板工具类】 4) Spring ORM spring对orm的支持: 既可以与hibernate整合,【session】 也可以使用spring的对hibernate操作的封装 5)Spring AOP 切面编程 6)SpringEE spring 对javaEE其他模块的支持
spring各个版本中:
在3.0以下的版本,源码有spring中相关的所有包【spring功能 + 依赖包】 如2.5版本;
在3.0以上的版本,源码中只有spring的核心功能包【没有依赖包】
(如果要用依赖包,需要单独下载!)
开发步骤:
1) 源码, jar文件:spring-framework-3.2.5.RELEASE
commons-logging-1.1.3.jar 日志 spring-beans-3.2.5.RELEASE.jar bean节点 spring-context-3.2.5.RELEASE.jar spring上下文节点 spring-core-3.2.5.RELEASE.jar spring核心功能 spring-expression-3.2.5.RELEASE.jar spring表达式相关表 以上是必须引入的5个jar文件,在项目中可以用户库管理!
2) 核心配置文件: applicationContext.xml
Spring配置文件命名方式:
applicationContext.xml / bean.xml
配置约束可以参考文档:spring-framework-3.2.5.RELEASE\docs\spring-framework-reference\htmlsingle\index.html
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 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>
实例:
applicationContext.xml(有时候创建的对象称bean对象是因为spring都是通过配置bean标签来得到对象)
<?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:p="http://www.springframework.org/schema/p" 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"> <!-- IOC容器的配置: 要创建的所有的对象都配置在这里 --> <bean id="user" class="cn.itcast.a_hello.User"></bean> </beans>
测试类:
public class Test { // 1. 通过工厂类得到IOC容器创建的对象 @Test public void testIOC() throws Exception { // 创建对象 // User user = new User(); // 现在,把对象的创建交给spring的IOC容器 Resource resource = new ClassPathResource("cn/itcast/a_hello/applicationContext.xml"); // 创建容器对象(Bean的工厂), IOC容器 = 工厂类 + applicationContext.xml BeanFactory factory = new XmlBeanFactory(resource); // 得到容器创建的对象 User user = (User) factory.getBean("user"); System.out.println(user.getId()); } //2. (方便)直接得到IOC容器对象 @Test public void testAc() throws Exception { // 得到IOC容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_hello/applicationContext.xml"); // 从容器中获取bean User user = (User) ac.getBean("user"); System.out.println(user); }}
spring控制对象创建的细节
applicationContext.xml配置参数的作用:
1) 对象创建数量: 单例/多例 scope="singleton", 默认值, 即 默认是单例 【service/dao/工具类】 scope="prototype", 多例; 【Action对象】 2) 什么时候创建? scope="prototype" 在用到对象的时候,才创建对象。 scope="singleton" 在启动(容器初始化), 就已经创建了bean,且整个应用只有一个。(单例想延迟初始化可以配置lazy-init=true) 3)是否延迟创建(该属性只是针对单例) lazy-init="false" (可不写)默认, 不延迟创建,即在启动时候就创建对象 lazy-init="true" 延迟初始化, 在用到对象的时候才创建对象(只对单例有效) 4) 创建对象之后,指定对象初始化/销毁时调用的方法。 init-method="init_user" 【对应对象的init_user方法,在对象创建之后执行 】 destroy-method="destroy_user" 【在调用容器对象的destriy方法时候执行,(容器用实现类ClassPathXmlApplicationContext】
实例:
public class User { private int id; private String name; public User() { super(); System.out.println("------User对象创建------"); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void init_user() { System.out.println("创建对象之后,初始化"); } public void destroy_user() { System.out.println("IOC容器销毁,user对象回收!"); }
配置:
<?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:p="http://www.springframework.org/schema/p" 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"> <!-- IOC容器的配置: 要创建的所有的对象都配置在这里--> <bean id="user" class="cn.itcast.a_hello.User" init-method="init_user" destroy-method="destroy_user" scope="singleton" lazy-init="false"></bean> </beans>
测试类:
public void testIOC() throws Exception { // 得到IOC容器对象 【用实现类,因为要调用销毁的方法】 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_hello/applicationContext.xml"); System.out.println("-----容器创建-----"); // 从容器中获取bean User user1 = (User) ac.getBean("user"); User user2 = (User) ac.getBean("user"); System.out.println(user1); System.out.println(user2); // 销毁容器对象 (ClassPathXmlApplicationContext类才有销毁方法)
ac.destroy();
}
spring实现创建对象的方式:
SpringIOC容器,是spring核心内容。
作用: 创建对象 & 处理对象的依赖关系
IOC容器创建对象: 有几种方式:
1) 调用无参数构造器
2) 带参数构造器
3) 工厂创建对象
工厂类,静态方法创建对象
工厂类,非静态方法创建对象
实例:
User.java
public class User { private int id; private String name; public User() { super(); System.out.println("------User对象创建【无参数构造器】------"); } public User(int id, String name) { System.out.println("-----User对象创建【带参数构造器】--------"); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } public void init_user() { System.out.println("创建对象之后,初始化"); } public void destroy_user() { System.out.println("IOC容器销毁,user对象回收!"); } }
ObjectFactory.java
// 工厂,创建对象 public class ObjectFactory { // 实例方法创建对象 public User getInstance() { return new User(100,"工厂:调用实例方法"); } // 静态方法创建对象 public static User getStaticInstance() { return new User(101,"工厂:调用静态方法"); }
bean.xml(配置文件名字可以自定义,可以放在src下也可以在包下)
<?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:p="http://www.springframework.org/schema/p" 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"> <!-- ###############对象创建############### --> <!-- 1. 默认无参数构造器 <bean id="user1" class="cn.itcast.b_create_obj.User"></bean> --> <!-- 2.1 带参数构造器 基本类型类型可以直接写,其他类型需要包名;index表示是第几个参数--> <bean id="user2" class="cn.itcast.b_create_obj.User"> <constructor-arg index="0" type="int" value="100"></constructor-arg> <constructor-arg index="1" type="java.lang.String" value="Jack"></constructor-arg> </bean> <!--2.2参数值还可以是其他对象, 如:定义一个字符串,值是"Jack" ; String s = new String("jack")--> <bean id="str" class="java.lang.String"> <constructor-arg value="Jacks"></constructor-arg> </bean> <bean id="user3" class="cn.itcast.b_create_obj.User"> <constructor-arg index="0" type="int" value="100"></constructor-arg> <constructor-arg index="1" type="java.lang.String" ref="str"></constructor-arg> </bean> <!-- 3. 工厂类创建对象 --> <!-- # 3.1 工厂类,实例方法 --> <!-- 先创建工厂 --> <bean id="factory" class="cn.itcast.b_create_obj.ObjectFactory"></bean> <!-- 在创建user对象,用factory方的实例方法 --> <bean id="user4" factory-bean="factory" factory-method="getInstance"></bean> <!-- # 3.2 工厂类: 静态方法 --> <!-- class 指定的就是工厂类型 factory-method 一定是工厂里面的“静态方法” --> <bean id="user" class="cn.itcast.b_create_obj.ObjectFactory" factory-method="getStaticInstance"></bean> <!--补充:对于静态方法的参数可以采用,类似有参数的构造器的配置的方式来,配置参数,实例见spring(2)中自定义AOP的实例-->
<!-- 对象写法 --> <!-- 问题:spring配置文件中,bean节点的id与name属性的区别? id 不能有特殊符号, 且唯一,且不能以数字开始 name 可以有特殊符号 --> <bean id="test" name="1test" class="cn.itcast.b_create_obj.User"></bean> </beans>
测试类:
public void testIOC() throws Exception { // 创建IOC容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/b_create_obj/bean.xml"); // 获取容器中的对象 User user = (User) ac.getBean("user"); System.out.println(user); }
处理对象依赖关系,Spring给对象的属性赋值【DI, 依赖注入】
(对象依赖的数据存放在属性中,属性可以是对象和基本类型,而将这些数据赋值给这些属性的过程就是依赖注入)
注入的方式有:
1) 通过构造函数 2) 通过set方法给属性注入值 3) p名称空间 4) 自动装配(了解) 5) 注解
构造函数,set属性,p名称空间的方式实例:
User.java
public class User { private int id; private String name; // --> 通过容器注入属性值 public void setId(int id) { this.id = id; } // //--> 通过容器注入属性值 public void setName(String name) { this.name = name; } public int getId() { return id; } public String getName() { return name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } public User() { super(); System.out.println("------User对象创建【无参数构造器】------"); } public User(int id, String name) { System.out.println("-----User对象创建【带参数构造器】--------"); this.id = id; this.name = name; }
UserAction.java
public class UserAction { // Service: springIOC容器注入 private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } public String execute() { userService.save(); return null; }
UserDao.java
public class UserDao { public void save() { System.out.println("DB:保存用户"); }
UserService.java
public class UserService { private UserDao userDao; // = new UserDao(); // IOC:对象的创建交给spring的外部容器完成 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void save() { userDao.save(); }
bean.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:p="http://www.springframework.org/schema/p" 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"> <!-- ###############对象属性赋值############### --> <!-- 1) 通过构造函数 --> <bean id="user1" class="cn.itcast.c_property.User" scope="prototype"> <constructor-arg value="100"></constructor-arg> <constructor-arg value="Tom"></constructor-arg> </bean> <!-- 2) 通过set方法给属性注入值(属性必须有set方法) --> <bean id="user" class="cn.itcast.c_property.User" scope="prototype"> <property name="id" value="101"></property> <property name="name" value="Jack"></property> </bean> <!-- 案例:set方法注入的是对象(配置的bean对象) action/service/dao --> <!-- dao instance --> <bean id="userDao" class="cn.itcast.c_property.UserDao"></bean> <!-- service instance --> <bean id="userService" class="cn.itcast.c_property.UserService"> <property name="userDao" ref="userDao"></property> </bean> <!-- action instance --> <bean id="userAction1" class="cn.itcast.c_property.UserAction"> <property name="userService" ref="userService"></property> </bean> <!-- ##############内部bean############## 缺点是不能复用bean--> <bean id="userAction2" class="cn.itcast.c_property.UserAction"> <property name="userService"> <bean class="cn.itcast.c_property.UserService"> <property name="userDao"> <bean class="cn.itcast.c_property.UserDao"></bean> </property> </bean> </property> </bean> </beans>
测试类:
public class App { // 创建容器对象 private ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/c_property/bean.xml"); @Test public void testSet() { // 从容器中获取 User user = (User) ac.getBean("user"); System.out.println(user); } @Test public void testExecuteAction() { // 从容器中获取Action UserAction userAction = (UserAction) ac.getBean("userAction"); userAction.execute(); }}
bean_p.xml(采用命名空间的标签的方式,属性对象也需要set方法):
<?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:p="http://www.springframework.org/schema/p" 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"> <!-- ###############对象属性赋值############### --> <!-- 给对象属性注入值: # p 名称空间给对象的属性注入值 (spring3.0以上版本才支持) --> <bean id="userDao" class="cn.itcast.c_property.UserDao"></bean> <bean id="userService" class="cn.itcast.c_property.UserService" p:userDao-ref="userDao"></bean> <bean id="userAction" class="cn.itcast.c_property.UserAction" p:userService-ref="userService"></bean> <!-- 传统的注入: <bean id="user" class="cn.itcast.c_property.User" > <property name="name" value="xxx"></property> </bean> --> <!-- p名称空间优化后 --> <bean id="user" class="cn.itcast.c_property.User" p:name="Jack0001"></bean> </beans>
测试类:
// 创建容器对象 private ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/c_property/bean_p.xml"); @Test public void testExecuteAction() { // 从容器中获取Action UserAction userAction = (UserAction) ac.getBean("userAction"); userAction.execute(); System.out.println(ac.getBean("user")); }
自动装配方式,分为:根据名称和类型自动装配(属性对象也需要set方法)
1.根据名称自动装配:autowire="byName"(自动去IOC容器(bean.xml配置)中找与属性名同名的引用的对象,并自动注入)
<!-- ###############自动装配############### --> <bean id="userDao" class="cn.itcast.d_auto.UserDao"></bean> <bean id="userService" class="cn.itcast.d_auto.UserService" autowire="byName"></bean> <!-- 根据“名称”自动装配: userAction注入的属性,会去ioc容器中自动查找与属性同名的对象 --> <bean id="userAction" class="cn.itcast.d_auto.UserAction" autowire="byName"></bean>
也可以定义到全局, 这样就不用每个bean节点都去写autowire=”byName”
<?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:p="http://www.springframework.org/schema/p" 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" default-autowire="byName"> 根据名称自动装配(全局) <!-- ###############自动装配############### --> <bean id="userDao" class="cn.itcast.d_auto.UserDao"></bean> <bean id="userService" class="cn.itcast.d_auto.UserService"></bean> <bean id="userAction" class="cn.itcast.d_auto.UserAction"></bean> </beans>
2.根据类型自动装配:autowire="byType"(必须确保依赖的类型在IOC容器中只有一个配置;否则报错)
<?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:p="http://www.springframework.org/schema/p" 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" default-autowire="byType"> <!-- ###############自动装配############### --> <bean id="userDao" class="cn.itcast.d_auto.UserDao"></bean> <bean id="userService" class="cn.itcast.d_auto.UserService"></bean> <!-- 如果根据类型自动装配: 必须确保IOC容器中依赖的类型只有一个该类型的对象 (userAction 依赖UserService类型的对象)--> <bean id="userAction" class="cn.itcast.d_auto.UserAction"></bean> <!-- 如果同时有下面的情况,报错: 因为上面已经有一个该类型的对象 <bean id="userService_test" class="cn.itcast.d_auto.UserService" autowire="byType"></bean> --> </beans>
(一般不推荐使用)Spring提供的自动装配简化配置,但是不利于后期的维护。(应该是依赖关系的可读性比较差,需要从类中确定)
测试类:
// 创建容器对象 private ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/d_auto/bean.xml"); @Test public void testExecuteAction() { // 从容器中获取Action UserAction userAction = (UserAction) ac.getBean("userAction"); userAction.execute(); }
注解方式,简化spring的IOC容器的配置
(注解的方式,属性对象不用提供set方法)
使用注解步骤:
1)先引入context名称空间:xmlns:context="http://www.springframework.org/schema/context" 2)开启注解扫描:<context:component-scan base-package="cn.itcast.e_anno2"></context:component-scan> 3)代码中使用注解
代码中相关的注解:Component/Resource
@Component :指定把一个对象加入IOC容器(还可以这样写@Component(‘属性名’),意思加入并且取名为xxx)
@Repository 作用同@Component; 在持久层使用(这样写,好像只是增强了可读性,层次比较清晰)
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
@Resource :属性注入,根据类型注入(还可以这样写@Resource(name="xxx")注入名为xxx的对象)
实例:
UserAction.java
//@Component("userAction") // 加入IOC容器 //@Component @Controller // 控制层的组件 public class UserAction { @Resource private UserService userService; public String execute() { userService.save(); return null; } }
UserDao.java(注解被注释掉了,是为测试注解和bean配置共同使用的情况)
// 把当前对象加入ioc容器 //@Component("userDao") // 相当于bean.xml 【<bean id=userDao class=".." />】 //@Component // 加入ioc容器的UserDao对象的引用名称, 默认与类名一样, 且第一个字母小写 //@Repository // 在持久层可以选择用这个注解 public class UserDao { public UserDao(){ System.out.println("UserDao.UserDao()"); } public UserDao(int id){ System.out.println("UserDao.UserDao(int id)" + id); } public void save() { System.out.println("DB:保存用户!!!"); } }
UserService.java
//@Component("userService") // userService加入ioc容器 //@Component @Service // 表示业务逻辑层的组件 public class UserService { //@Resource // 根据类型查找 【在容器中要确保该类型只有一个变量,针对的是注解和配置bean一起使用的情况,如果都是采用注解,只会一个类型加入IOC容器】 @Resource(name = "userDao")// 根据名称查找 private UserDao userDao; // 去容器中招UserDao类型的变量,找到后就赋值 public void save() { userDao.save(); } }
bean.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:p="http://www.springframework.org/schema/p" 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="cn.itcast.e_anno2"></context:component-scan>
//注释掉了userDao中注解(注解和配置bean可以互补的方式共同使用) <bean id="userDao" class="cn.itcast.e_anno2.UserDao" scope="prototype"> </bean> </beans>
测试类:
// 创建容器对象 private ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/e_anno2/bean.xml"); @Test public void testExecuteAction() { // 从容器中获取Action UserAction userAction = (UserAction) ac.getBean("userAction"); userAction.execute(); }
总结:
一种更加简便的依赖注入方式,那就是注解加自动装配,加入容器的对象添加注解,依赖的对象注入交给自动装配的方式注入(这样依赖的属性对象不用写注解,但需要写set方法,因为交个自动装配的方式)

浙公网安备 33010602011771号