1.简述
Spring框架是个轻量级的JavaEE框架,即不需要依赖容器就能运行.Struts和Hibernate也是轻量级的.
Spring以IOC(Inversion Of Control控制反转)和AOP(Aspect Oriented Programming面向切面编程)为主要思想.
Spring也可称为DI(Dependency Injection,依赖注入).
IOC,把创建和查找依赖对象的控制权交给spring容器,即对象的生命周期由容器控制,由容器进行注入程序需要该对象的地方,这样可以降低模块与模块之间的耦合,可以使程序结构更灵活;AOP,用于处理系统中处于各个模块的横切关注点,如事务、日志等,让程序更关注与业务逻辑的实现。
2.Spring简单应用体验
1).配置
<bean id="user" class="cn.spring.b_ioc.User" init-method="user_init" destroy-method="user_destroy" lazy-init="false" scope="singleton"></bean>
2).根据配置获取对象
// 加载容器applicationContext.xml配置文件,创建IOC容器对象!
ApplicationContext ac = new ClassPathXmlApplicationContext("cn/spring/b_ioc/applicationContext.xml");
// 从容器中获取对象
User user = (User) ac.getBean("user7");
//对象在启动时,创建IOC容器时创建bean.xml配置中的对象,getBean()方法只是获取容器中的对象.
3. Spring配置文件创建对象
<!-- 1. 默认无参数构造函数,创建对象
<bean id="user1" class="cn.spring.b_ioc.User"></bean>-->
<!-- 2. 带参数构造函数,创建对象 -->
<!-- 需求: 创建String对象,值是“Jack” String s = new String("jack"); -->
<bean id="str" class="java.lang.String">
<constructor-arg value="jack"></constructor-arg>
</bean>
<!-- 需求2: 创建user(100,tom)对象
<bean id="user2" class="cn.spring.b_ioc.User">
<constructor-arg type="int" value="100"></constructor-arg>
<constructor-arg type="java.lang.String" value="tom"></constructor-arg>
</bean>
-->
<!-- 需求3: 创建user(100,jack)对象 -->
<!--
index 构造函数参数的索引
type 参数类型
value 参数的值
ref 参数的值引用的是IOC容器中的对象!
<bean id="user3" class="cn.spring.b_ioc.User">
<constructor-arg index="0" type="int" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" ref="str"></constructor-arg>
</bean>
-->
<!-- 工厂创建对象 【spring在工厂类,调用“静态方法” 的时候,不会创建工厂对象!】 -->
<!-- 方式1: 静态方法
<bean id="user4" class="cn.spring.b_ioc.BeanFactory" factory-method="getUserByStatic"></bean>
-->
<!-- 方式2:调用工厂类,非静态方法 -->
<bean id="factory" class="cn.spring.b_ioc.BeanFactory"></bean>
<bean id="user4" factory-bean="factory" factory-method="getUser"></bean>
4. Spring配置文件的一些细节
配置文件命名:applicationContext.xml或bean*.xml1) 容器创建对象,默认是单例:scope="singleton" 【dao/service】
2) 多例:scope="prototype" 【action】
scope="singleton" 默认是单例,在创建IOC容器对象的时候创建对象!
scope="prototype" 每次从容器获取对象的时候创建对象(执行getBean方法)
3) 对象创建时间
只要启动时候创建IOC容器对象,
那么,单例的对象,就在启动时候创建了; 多例对象在访问时候创建.
4) 单例的对象,也能在第一次使用的时候创建:
lazy-init="true" 在创建容器时候不创建单例对象,在第一次访问时候创建单例对象.
默认false,表示不延迟初始化,即创建容器创建单例对象.
lazy-init 属性对多例的对象无效,没有影响. 多例,始终是用的时候,才创建对象.
5) 创建对象后执行初始化与销毁:
init-method 在创建对象之后执行.
destroy-method 在调用容器对象的destroy()方法的时候执行.
(必须用容器的实现类, 接口中没有定义这个方法)
单例: 执行一次初始化,在容器销毁时执行销毁方法.
多例: 访问几次,执行几次初始化操作. 不会执行销毁对象的方法.
6).id与name区别:
共同点: 都可以引用ioc容器中对象.
区别:
id 唯一,不能以数字开头. 不能有特殊符合 [不符合XML规范]
一次只能用一个名称,否则报错.(编译报错、运行报错)
name 可以以数字开头,可以有特殊符号.
可以一定定义多个名称,用空格或逗号隔开.
5. 依赖注入
IOC容器,可以在创建对象后,处理对象的依赖关系. 给对象属性赋值(注入)值.DI , dependency injection即依赖注入.(6中方式)
如:
public class User {
public User(int id, String name) {
this.id = id;
this.name = name;
}
public User() {
}
private int id;
private String name;
// 提供set方法; 接收Spring容器注入的值
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
<!-- 1) 通过构造器注入值 -->
<bean id="user1" class="cn.spring.c_di.User">
<constructor-arg value="1000"></constructor-arg>
<constructor-arg value="rose"></constructor-arg>
</bean>
<!-- 2) 通过set方法注入值 -->
<bean id="user2" class="cn.spring.c_di.User">
<property name="id" value="10000"></property>
<property name="name" value="jack"></property>
</bean>
<!-- 3) p 名称空间注入值 (简化赋值操作)-->
<!-- 同property属性植入值一样; p:id id是值属性(setId 中的id属性!) -->
<bean id="user3" class="cn.spring.c_di.User" p:id="10000" p:name="jack"></bean>
<!-- 可引用当前配置中的bean -->
<bean id="str" class="java.lang.String">
<constructor-arg value="jack"></constructor-arg>
</bean>
<bean id="user" class="cn.spring.c_di.User" p:id="10000" p:name-ref="str"></bean>
-------------------------------------------------------------
===模拟web的dao/service/action,使用set注入创建对象
//Dao层
public class UserDao implements IUserDao {
public void save() {
System.out.println("MySQL保存......");
}
}
//service层
public class UserService implements IUserService {
// 接收IOC容器注入的dao实例
private IUserDao userDao;
public void setUserDao(IUserDao userDao){ // 传入实现类.
this.userDao = userDao;
}
@Override
public void save() {
// 调用dao
userDao.save();
}
}
//action层
public class UserAction {
private IUserService userService;
public void setUserService(IUserService userService) {
this.userService = userService;
}
// 模拟Action处理请求
public String execute(){
// 调用Service
userService.save();
return "";
}
}
<!-- dao实例 , 加入ioc容器-->
<bean id="userDao" class="cn.spring.d_di_eg.UserDao"></bean>
<!-- service实例 -->
<bean id="userService" class="cn.spring.d_di_eg.UserService"> <!-- 创建对象, 控制反转 -->
<property name="userDao" ref="userDao"></property> <!-- 依赖注入 ref引用上面的userDao -->
</bean>
<!-- action实例 -->
<bean id="userAction" class="cn.spring.d_di_eg.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
<!-- 3) p 名称空间注入值
<bean id="userDao" class="cn.spring.d_di_eg.UserDao_oracle"></bean>
<bean id="userService" class="cn.spring.d_di_eg.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="cn.spring.d_di_eg.UserAction" scope="prototype" p:userService-ref="userService"></bean>
-->
<!-- 4) 内部bean方式
注意:内部bean只被引用一次! 写法更紧凑!
课后测试: 1. 内部bean能否给id! 2. 对象是多例,内部bean是多例还是单例?
<bean id="userAction" class="cn.spring.d_di_eg.UserAction" scope="prototype">
<property name="userService">
<bean class="cn.spring.d_di_eg.UserService">
<property name="userDao">
<bean class="cn.spring.d_di_eg.UserDao_oracle"></bean>
</property>
</bean>
</property>
</bean>
-->
<!-- 5) 自动装配(了解) -->
<!--
autowire="byName" 根据名称自动装配
当前对象的set方法,会自动去容器匹配对象,然后注入到set方法中.
autowire="byType" 根据类型自动装配,只要容器有这个类型,就注入.()根名称无关.)
注意: bean中只有有唯一的这个类型的对象.否则报错.
default-autowire="byName" 全局配置
在配置文件的根节点写“根据名称自动装配”,表示当前配置文件所有的bean都采用这种装配.
总结:
1. 简化了配置.属性的依赖注入,交给spring去自动完成(装配).
2. 不建议使用, 维护起来一旦出错,找错麻烦.
<bean id="userDao" class="cn.spring.d_di_eg.UserDao_oracle"></bean>
<bean id="userService" class="cn.spring.d_di_eg.UserService"></bean>
<bean id="userAction" class="cn.spring.d_di_eg.UserAction" scope="prototype"></bean>
-->
<!-- 6) 注解方式 -->
<!-- 6.1 引入context名称空间 -->
<!-- 6.2 开启注解扫描 -->
<!-- base-package 在创建容器的时候,会扫描指定的包! -->
<context:component-scan base-package="cn.spring.e_anno2"></context:component-scan>
//dao层
@Repository
public class UserDao_oracle implements IUserDao {
@Override
public void save() {
System.out.println("Oracle的保存操作......");
}
}
//service层
@Service // 同上; 用于表示是“业务逻辑层组件”
public class UserService implements IUserService {
@Resource // 默认从容器找名称是“userDao”对应的对象,再赋值.
private IUserDao userDao;
public void save() {
userDao.save();
}
}
//action层
@Scope("prototype") // 指定对象是多例
@Controller // 同@Component 用于表示是控制层的组件(类)
public class UserAction {
@Resource // 自动从容器找“userService” 对应的对象!
private IUserService userService;
public String execute(){
userService.save();
return "";
}
}
//注意:@Repository @Service @Controller @Component 都是一个意思,标识了IOC容器中的对象.
只是为了更容易阅读.
这些注释等同于<bean>节点,而@Resource等同于<property>节点.
//当然,@Resource的字段名要与其类型对应的类的对象名一致,否则,无法自动匹配.
6. Spring与Struts整合
(各层代码与struts框架一样(只是添加了Spring框架的注解),所以代码略,只记录配置)
<!--*************** web.xml *************** -->
<!-- 1. struts2核心过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- SpringIOC容器初始化! -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/bean*.xml</param-value>
</context-param>
<!-- 监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--*************** struts.xml ***************-->
<!--
class 根据名称 从ioc容器获取创建的action对象.
还可以根据类型去容器找Action对象.
class="userAction"
class="cn.spring.action.UserAction"
-->
<action name="user" class="userAction">
<result>/index.jsp</result>
</action>
<!--*************** bean.xml *************** -->
<!-- 注解方式创建对象 , 加入ioc容器-->
<context:component-scan base-package="cn.spring"></context:component-scan>
<!-- 代码中各类或字段方法,都要写上相应的注解 -->
<!-- 若各层类中不写注解,可以用set方式注入 -->
*若有不足或错误,请多多指教,谢谢!*