Sping在解决什么问题
- 程序自检的耦合(依赖)--必须依赖mysql的jar包
DriverManager.registerDriver(new com.mysql.jdbc.Driver);
- 三层架构中的解耦过程--对象的创建方式
1.强依赖关系 --通过new生成对象
UserDao userDao = new UserDaoImpl();
2. 使用反射获取对象
Object object = Class.forName(properties.get(beanName).toString()).newInstance();
3.声明beanFactory获取对象
public static Object getBean(String beanName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Object object = Class.forName(properties.get(beanName).toString()).newInstance();
return object;
}
- BeanFactory工具类和bean.properties配置文件
1.bean.properties配置文件--键值对形式,后面是类的路径
userDaoImpl=com.bj169.dao.impl.UserDaoImpl
userServiceImpl=com.bj169.service.impl.UserServiceImpl
2.BeanFactory工具类,读取Properties类读取配置文件
package com.bj169.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class BeanFactory {
private static Properties properties = null;
static {
//必须初始化properties
properties = new Properties();
//通过当前类获取配置文件的输入流InputStream
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
try {
//加载输入流
properties.load(resourceAsStream);
} catch (ExceptionInInitializerError e) {
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object getBean(String beanName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//通过get方法获取指定beanName的类路径,在通过反射获取对象
Object object = Class.forName(properties.get(beanName).toString()).newInstance();
return object;
}
}
@Test
public void test2() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
//获取配置文件中key为userServiceImpl的类对象
UserService userService = (UserService) BeanFactory.getBean("userServiceImpl");
userService.addUser();
}
- 使用ResourceBundle优化BeanFactory,用Map容器保存key与对象的映射信息 --控制反转IOC底层实现的原理
package com.bj169.util;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
/**
* @ClassName BeanFactory1
* @Description TODO
* @Author Administrator
* @Date 2018/12/11 0011 11:43
* @Version 1.0
**/
public class BeanFactory1 {
//直接读取名字为bean.properties的配置文件,底层封装
private static ResourceBundle resourceBundle = ResourceBundle.getBundle("bean");
//存放配置文件里的key和对象的映射关系
private static Map<String, Object> beanMap = new HashMap<String, Object>();
static {
//获取配置文件的所有key
Enumeration<String> keys = resourceBundle.getKeys();
while (keys.hasMoreElements()) {
String beanName = keys.nextElement();
try {
//得到beanName对应的object对象 把beanName和对应的对象一起存放在map中
Object object = Class.forName(resourceBundle.getString(beanName)).newInstance();
beanMap.put(beanName, object);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public static Object getBean(String beanName) {
//通过beanName获取相应的对象
Object object = beanMap.get(beanName);
return object;
}
}
至此,直接依赖(编译期)关系转为了间接依赖(运行期)
创建对象的权利(控制权)交出,降低依赖关系(解耦)
本质上只做一件事儿:解决层次之间的依赖关系
Spring在做什么??
–轻量级:Spring 是非侵入性的 - 基于 Spring 开发的应用中的对象可以不依赖于 Spring 的 API
–依赖注入(DI --- dependency injection、IOC)
–面向切面编程(AOP --- aspect oriented programming)
–容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期
–框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 Java 注解组合这些对象
–一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库 (实际上 Spring 自身也提供了展现层的 SpringMVC 和 持久层的 Spring JDBC)
- 建立第一个Spring项目,通过idea搭建,选择自动导包和添加配置文件spring-config.xml,不需要进行写BeanFactory,以及封装好两种IOC容器,ApplicationContext(主要)和BeanFactory,下面举例说明。
spring-config.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.bj169.entity.User" scope="prototype">
<property name="name" value="杜沛"></property>
<property name="age" value="23"></property>
</bean>
<bean id="userFactory" factory-method="getUser" class="com.bj169.factory.UserFactory"></bean>
</beans>
package com.bj169.test;
import com.bj169.entity.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
/**
* @ClassName TestDemo
* @Description TODO
* @Author Administrator
* @Date 2018/12/11 0011 9:34
* @Version 1.0
**/
public class TestDemo {
//IOC的两种容器,ApplicationContext和BeanFactory
ApplicationContext context = null;
BeanFactory beanFactory = null;
@Before
public void before() {
//读取配置文件
context = new ClassPathXmlApplicationContext("spring-config.xml");
}
@Before
public void before1() {
//读取配置文件
beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
}
@Test
public void test1() {
//获取bean对象,立刻加载
User user1 = (User) context.getBean("user");
System.out.println(user1);
}
@Test
public void test2() {
//BeanFactory获得的对象为延迟加载
User user = (User) beanFactory.getBean("user");
System.out.println(user);
}
}
- 配置文件spring-config的注意事项
•配置 bean
–配置形式:基于 XML 文件的方式;基于注解的方式
–Bean 的三种实例化方式:通过全类名(反射主要)、通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean
–IOC 容器: BeanFactory & ApplicationContext(主要) 概述
–依赖注入的方式:属性注入;构造器注入
–注入属性值细节
–自动转配
–bean 之间的关系:继承;依赖
–bean 的作用域:singleton(单例);prototype(多实例);默认的是单例,在bean中通过scope属性设置,WEB 环境作用域
–使用外部属性文件
–spEL
–IOC 容器中 Bean 的生命周期
Spring 4.x 新特性:泛型依赖注入
- IOC和DI概念
•IOC(Inversion of Control):其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
DI(Dependency Injection) — IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入. 相对于 IOC 而言,这种表述更直接
- Spring 中的三种依赖注入方式:属性注入,构造器注入,工厂方法注入(少用) ----DI
<?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="user" class="com.bj169.entity.User" scope="prototype">
<!--构造方法给对象赋值,构造器注入-->
<!--<constructor-arg value="陈苗" name="name"></constructor-arg>-->
<!--<constructor-arg value="20" name="age"></constructor-arg>-->
<property name="name" value="杜沛"></property>
<property name="age" value="17"></property>
<!--属性注入-->
<property name="list">
<list>
<value>手机</value>
</list>
</property>
<property name="strings">
<list>
<value>1000元</value>
</list>
</property>
<property name="map">
<map>
<entry key="1" value="学生"></entry>
</map>
</property>
<!--ref引用其它Bean-->
<property name="date" ref="date1">
</property>
</bean>
<!--date是一个对象,需要声明Bean-->
<bean name="date1" class="java.util.Date">
</bean>
</beans>
- 使用 utility scheme 定义集合 --声明list Bean,在配置文件里面要添加 util schema 定义
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="newuser" class="com.bj169.entity.newUser">
<property name="name" value="杜沛"></property>
<!--newUser类里有一个list<Article>属性,通过声明一个list<Article> Bean来引入属性值-->
<property name="list" ref="list"></property>
</bean>
<bean id="art" class="com.bj169.entity.Article">
<property name="name" value="厚黑学"></property>
<property name="price" value="100"></property>
</bean>
<bean id="art1" class="com.bj169.entity.Article">
<property name="name" value="三国演义"></property>
<property name="price" value="10"></property>
</bean>
<!--声明list的Bean,所有外部Bean可以通过id引入这个list Bean-->
<util:list id="list">
<!--list Bean里引入其他bean-->
<ref bean="art"></ref>
<ref bean="art1"></ref>
</util:list>
</beans>
- 使用 p 命名空间,同样要在配置文件里面添加p命名空间的定义
<bean id="art" class="com.bj169.entity.Article" p:name="杜沛">
<!--上面通过p给name属性赋值的效果和下面properties的效果一样-->
<!--<property name="name" value="厚黑学"></property>-->
<property name="price" value="100"></property>
</bean>
-
关于注解
•组件扫描(component scanning): Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件.
•特定组件包括:
–@Component: 基本注解, 标识了一个受 Spring 管理的组件(Pojo) --用在一些实体类上
–@Repository: 标识持久层组件 (DAO: UserDao <-> UserRepository)
–@Service: 标识服务层(业务层)组件: 注入DAO: UserService(UserServiceImpl)
–@Controller: 标识控制层(Action): 注入Service UserController
•对于扫描到的组件, Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写. 也可以在注解中通过 value 属性值标识组件的名称
注意:
•当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan> :
–base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类.
–当需要扫描多个包时, 可以使用逗号分隔.
如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类,
<?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">
<context:component-scan base-package="com.bj169"></context:component-scan>
- @Autowired 自动装配 Bean
-@Autowired 注解自动装配具有兼容类型的单个 Bean属性
–构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解
–默认情况下, 所有使用 @Authwired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false
默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称
@Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配.
@Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean.
@Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("userDaoImpl")
private UserDao userDao ;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser(myUser myUser) {
userDao.add(myUser);
}
}
@Repository
public class UserDaoImpl implements UserDao {
private Session session = null;
public void setSession(Session session) {
this.session = session;
}
@Override
public void add(myUser myUser) {
System.out.println("session" + session);
System.out.println(session.toString());
session.save(myUser);
System.out.println("chenggong");
}
}