* IOC&DI概述
1 IOC (Inversion of Control),控制反转:生成对象的控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
2 DI (Dependency Injection),依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依 赖关系注入到组件之中
3 依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同
4 依赖注入:
是从应用程序的角度在描述,应用程序依赖容器创建并注入它所需要的外部资源
5 控制反转
从容器的角度在描述,容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源
6 好处是解耦
* 自定义IOC框架
思考:能不能独立构造一个对象工厂,在对象创建工厂中建立好项目需要的对象?
好处:哪里需要对象,都是从对象工厂获取,方便集中地管理对象!!!
* 前置知识:dom4j,反射,..
* 前期准备
public class User implements Serializable {
private int id;
private String username;
private String psw;
private char sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPsw() {
return psw;
}
public void setPsw(String psw) {
this.psw = psw;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public User(int id, String username, String psw, char sex) {
this.id = id;
this.username = username;
this.psw = psw;
this.sex = sex;
}
public User() {
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return id == user.id &&
sex == user.sex &&
Objects.equals(username, user.username) &&
Objects.equals(psw, user.psw);
}
@Override
public int hashCode() {
return Objects.hash(id, username, psw, sex);
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", psw='" + psw + '\'' +
", sex=" + sex +
'}';
}
}
public interface UserDao {
public void addUser(User user);
}
public class UserDaoImpl implements UserDao {
@Override
public void addUser(User user) {
System.out.println("addUser");
}
}
public interface UserService {
public void reg(User user);
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void reg(User user) {
userDao.addUser(user);
}
}
* 添加dom4j的依赖
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
* 编写BeanFactory
public class BeanFactory {
/**
* 存储对象
* key:对象别名(其实就是id)
* value:具体的对象
*/
private static HashMap<String,Object> beans=new HashMap<String, Object>();
public BeanFactory(String path){
InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream(path);
SAXReader reader=new SAXReader();
try {
Document doc = reader.read(is);
// 获得根节点
Element root = doc.getRootElement();
// 获取所有bean节点
List<Element> beanElements = root.elements();
for (Element beanElement:beanElements){
// 对象别名
String id = beanElement.attributeValue("id");
String className = beanElement.attributeValue("class");
// 通过反射产生对象
Object obj = Class.forName(className).newInstance();
// 存放对象
beans.put(id,obj);
}
// 处理:property 标签
for (Element beanElement:beanElements){
List<Element> propertyElements = beanElement.elements("property");
if(propertyElements!=null){
// 处理多个properties标签
// 从容器获得当前的对象
Object obj = beans.get(beanElement.attributeValue("id"));
for(Element propertyElement:propertyElements){
String name = propertyElement.attributeValue("name");
String ref = propertyElement.attributeValue("ref");
// 从容器获取需要被赋值的对象
Object refObj = beans.get(ref);
// 获得当前的对象的setter方法并把需要被赋值的对象设置进去
// 构建setter的方法
// setUserDao
String setter="set"+name.substring(0,1).toUpperCase()+name.substring(1);
Method method = obj.getClass().getDeclaredMethod(setter, refObj.getClass().getInterfaces());
// 调用setter的方法
method.invoke(obj,refObj);
}
}
}
} catch (DocumentException | ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 通过别名获取对象
* @param name
* @return
*/
public Object getBeans(String name){
return beans.get(name);
}
}
<?xml version="1.0" encoding="utf-8"?>
<beans>
<bean id="userDao" class="com.hx.hx02.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hx.hx02.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
@Test
public void test1(){
// 获得UserServiceImpl的对象,通过BeanFactory
BeanFactory factory=new BeanFactory("beans.xml");
UserService userService = (UserService) factory.getBeans("userService");
User user=new User();
userService.reg(user);
}
* 开发Spring IOC
* 使用spring模式创建工程
* 复制其他工程的User,UserDao,UserDaoImpl
public class App {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
User user=new User();
userDao.addUser(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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.hx.spring.dao.UserDaoImpl"></bean>
</beans>
* Spring 常见jar介绍
Spring Aspects:Spring提供的对AspectJ框架的整合
Spring Beans:Spring IOC的基础实现,包含访问配置文件、创建和管理bean等。
Spring Context:在基础IOC功能上提供扩展服务,此外还提供许多企业级服务的支持,有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持。
Spring Context Support:Spring context的扩展支持,用于MVC方面。
Spring Core:Spring的核心工具包
Spring expression:Spring表达式语言
Spring Framework Bom:
Spring Instrument:Spring对服务器的代理接口
Spring Instrument Tomcat:Spring对tomcat连接池的集成
Spring JDBC:对JDBC 的简单封装
Spring JMS:为简化jms api的使用而做的简单封装
Spring Messaging:是spring4.0为了集成jms发布的一个新模块,只有spring 4.0以后才支持
Spring orm:整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
Spring oxm:Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换
Spring test:对JUNIT等测试框架的简单封装
Spring tx:为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。
Spring web:包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。
Spring webmvc:包含SpringMVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类。
Spring webmvc portlet:Spring MVC的增强
必须引入的5个jar文件:
commons-logging-xxx.jar [日志处理]
spring-beans-xxx.RELEASE.jar [读取bean节点]
spring-context-xxx.RELEASE.jar [spring上下文处理]
spring-core-xxx.RELEASE.jar [spring核心功能]
spring-expression-xxx.RELEASE.jar [spring表达式处理]
* Spring maven 的构建方式
* 创建普通的quickstart骨架的Java项目
* 添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
* 在resources 目录下创建spring-config文件
<?xml version="1.0" encoding="UTF-8"?>
<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.hx.hx02.dao.UserDaoImpl"></bean>
</beans>
@Test
public void test1(){
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
User user=new User();
userDao.addUser(user);
}
* SpringIOC的核心接口工厂
* ApplicationContext
1 使用ApplicationContext工厂的接口,使用该接口可以获取到具体的Bean对象
2 该接口下有两个具体的实现类
1) ClassPathXmlApplicationContext: 加载类路径下的Spring配置文件
2) FileSystemXmlApplicationContext:加载本地磁盘下的Spring配置文件
* BeanFactory(Spring 早期的形式)
@Test
public void test2() {
BeanFactory beans = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
UserDao userDao = (UserDao) beans.getBean("userDao");
User user=new User();
userDao.addUser(user);
}
* BeanFactory和ApplicationContext的区别
1 BeanFactory :BeanFactory采取延迟加载,第一次getBean时才会初始化Bean
2 ApplicationContext :在加载spring-config.xml时候就会创建具体的Bean对象的实例,还提供了一些其他的功能
* SpringIOC 创建对象方式
public class User implements Serializable {
private int id;
private String username;
private String psw;
private char sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPsw() {
return psw;
}
public void setPsw(String psw) {
this.psw = psw;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public User(int id, String username, String psw, char sex) {
System.out.println("User对象创建----有参数");
this.id = id;
this.username = username;
this.psw = psw;
this.sex = sex;
}
public User() {
System.out.println("User对象创建----无参数");
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return id == user.id &&
sex == user.sex &&
Objects.equals(username, user.username) &&
Objects.equals(psw, user.psw);
}
@Override
public int hashCode() {
return Objects.hash(id, username, psw, sex);
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", psw='" + psw + '\'' +
", sex=" + sex +
'}';
}
}
* 无参数的构造方法
* 有参数的构造方法
<bean id="user" class="com.hx.hx02.bean.User">
<constructor-arg name="id" type="int" value="10001"/>
<constructor-arg name="username" type="java.lang.String" value="xiaohei"/>
<constructor-arg name="psw" type="java.lang.String" value="123123"/>
<constructor-arg name="sex" type="char" value="男"/>
</bean>
按照顺序可以不写
<bean id="user" class="com.hx.hx02.bean.User">
<constructor-arg value="10001"/>
<constructor-arg value="xiaohei"/>
<constructor-arg value="123123"/>
<constructor-arg value="男"/>
</bean>
@Test
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
* 工厂类的创建的方式
public class UserFactory {
public User getInstance(){
return new User(10002,"小黑","123123",'男');
}
public static User getStaticInstance(){
return new User(10002,"小黑","123123",'男');
}
}
<bean id="factory" class="com.hx.hx02.bean.UserFactory"></bean>
<bean id="user1" factory-bean="factory" factory-method="getInstance"/>
<bean id="user2" class="com.hx.hx02.bean.UserFactory" factory-method="getStaticInstance"></bean>
@Test
public void test4() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
User user1 = (User) context.getBean("user1");
User user2 = (User) context.getBean("user2");
System.out.println(user1);
System.out.println(user2);
}