Spring
说明下【本文是在网上听课做的笔记,代码是自己敲的,有些文字是复制的老师发的】
Spring框架介绍
Spring是一个轻量级的IoC和AOP的框架
IoC
控制反转
AOP
面向切面编程
Spring的功能
优点:
1)方便解耦,简化开发
Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。
2)方便集成各种优秀框架
Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis
等)的直接支持。
3)降低 Java EE API 的使用难度
Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些
API 应用的难度大大降低。
4)方便程序的测试
Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。
5)AOP 编程的支持
Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。
6)声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无须手动编程。
接口和Spring 是完美搭配
以前
public interface UserDAO{ void save(); } public class UserDAOImpl implements UserDAO{ public void save(){ .... } } public class UserServiceImpl implements UserService{ private UserDAO userDAO = new UserDAOImpl(); public void reg(){ userDAO.save(); } } ---------------------------------------------------- public class UserDAOJDBCImpl implements UserDAO{ public void save(){ .... } } public class UserServiceImpl implements UserService{ private UserDAO userDAO; public void reg(){ userDAO.save(); .... } } 我们在UserServiceImpl中不再实例化DAO对象 从Spring容器中获得
搭建Spring环境
1、添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.18.RELEASE</version> </dependency>
2、编写bean
package cn.cqie.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private String uname; private String upwd; }
3、编写配置文件
先将模板在idea中生成
<?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"> <!-- User user = new User(); <bean> 声明实例化对象的信息 id 对象的名称 class 对象的类型 --> <bean id="user" class="cn.cqie.pojo.User"></bean> </beans>
4、测试获取user对象
package cn.cqie.test; import cn.cqie.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppTest { @Test public void test(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app.xml"); User user = (User) applicationContext.getBean("user"); System.out.println("AppTest.test"+user); user.setUname("yx"); user.setUpwd("123"); System.out.println(user); } }
IOC容器介绍
BeanFactory
在没有获取容器中实例时,不实例化对应的对象
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("app.xml")); BeanFactory beanFactory1 = new XmlBeanFactory(new FileSystemResource("d:/app.xml"));
ApplicationContext
ApplicationContext applicationContext2 = new FileSystemXmlApplicationContext("d:/app.xml"); ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app.xml"); ApplicationContext applicationContext3 = new AnnotationConfigApplicationContext(JavaConfig.class); User user = (User) applicationContext3.getBean("user"); System.out.println("AppTest.test"+user); user.setUname("yx"); user.setUpwd("123"); System.out.println(user);
容器生成时,就会实例化配置文件中声明的对象
ApplicationContext从BeanFactory派生出来的
ApplicationContext增加了以下功能
- 国际化(MessageSource)
- 访问资源,如URL和文件(ResourceLoader)
- 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
- 消息发送、响应机制(ApplicationEventPublisher)
- AOP(拦截器)
获取实例的简单的底层原理
package cn.cqie.util; import cn.cqie.pojo.User; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; public class MyClassPathXmlApplicationContext { Map<String,Object> container = new HashMap<>(); public MyClassPathXmlApplicationContext(String resource){ //获得resource对应的文件路径 或者 输入流 InputStream inputStream = null; try { inputStream = new FileInputStream(new File(resource)); } catch (FileNotFoundException e) { e.printStackTrace(); } //使用xml 解析技术(dom4j)读取xml文件的信息 SAXReader reader = new SAXReader(); try { Document document = reader.read(inputStream); //读出标签<bean>、属性(id 、 class) 及值 (user 、 cn.cqie.pojo.User) Element rootElement = document.getRootElement(); List<Element> elements = rootElement.elements(); for (Element element:elements){ System.out.println(element.getName()); List<Attribute> attributes = element.attributes(); String id = ""; String clazz = ""; for (Attribute attribute:attributes){ if(attribute.getName().equals("id")){ id = attribute.getValue(); System.out.println("id :"+id); }else{ if(attribute.getName().equals("class")){ clazz = attribute.getValue(); System.out.println("clazz :"+ clazz); } } } //使用反射生成实例 Class<?> aClass = Class.forName(clazz); Object obj = aClass.newInstance(); //使用Map存储id和对应的实例 container.put(id,obj); } } catch (DocumentException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } public Object getBean(String id){ return container.get(id); } public static void main(String[] args) { MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("f:/app2.xml"); User user = (User) context.getBean("user"); user.setUname("tcx"); System.out.println("user :"+user); } }
Bean的概念
Spring中Bean就是一个类的实例
<bean id="" class="" />
Bean的生成方式有三种:
1、构造器生成
<?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"> <!-- 通过构造器生成 cn.cqie.pojo.User 必须有为空的构造器 --> <bean id="user" class="cn.cqie.pojo.User"/> </beans>
@Test public void testConstructor(){ System.out.println(66); ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app2.xml"); User user = (User) applicationContext.getBean("user"); user.setUname("constructor "); System.out.println(user); }
2、静态工厂
//UserStaticFactor.java package cn.cqie.util; import cn.cqie.pojo.User; public class UserStaticFactor { public static User getUser(){ return new 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"> <!-- 通过静态工厂生成 User user = UserStaticFactor.getUser(); --> <bean id="user2" class="cn.cqie.util.UserStaticFactor" factory-method="getUser"/> </beans>
@Test public void testStaticFactor(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app2.xml"); User user2 = (User) applicationContext.getBean("user2"); user2.setUname("static factory"); System.out.println(user2); }
3、实例工厂
// UserInstanceFactor.java package cn.cqie.util; import cn.cqie.pojo.User; public class UserInstanceFactor { public User getUser(){ return new 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"> <!-- 实例化工厂构造 UserInstanceFactor userInstanceFactor = new UserInstanceFactor(); User user = userInstanceFactor.getUser(); --> <bean id="userInstanceFactor" class="cn.cqie.util.UserInstanceFactor" /> <bean id="user3" factory-bean="userInstanceFactor" factory-method="getUser"/> </beans>
@Test public void testInstanceFactor(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app2.xml"); User user3 = (User) applicationContext.getBean("user3"); user3.setUname("Instance factor "); }
Bean的作用域范围
scope有如下五个取值:
singleton:单例的(默认的),使用singleton定义的Bean是单例的,每次调用getBean都是调用的同一个对象。只要IoC容器一创建就会创建Bean的实例。
prototype:多例的,每次通过Spring IoC容器获取prototype定义的Bean时,容器都将创建一个新的Bean实例。创建时不会实例该Bean,只有调用getBean方法时,才会实例化。
request:作用于web的请求范围,在每一次HTTP请求时,容器会返回Bean的同一个实例,对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Request内有效。
session:作用于web的会话范围,在一次HTTP Session中,容器会返回该Bean的同一个实例,对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Session内有效。
global-session:作用于集群环境的会话范围(全局会话范围),在一个全局的HTTP Session中,容器返回Bean的同一个实例。当不是集群环境时,它就是session。
<?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="cn.cqie.pojo.User" scope="prototype"/> </beans>
@Test public void testScope(){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("app3.xml"); User user = (User) applicationContext.getBean("user"); User user2 = (User) applicationContext.getBean("user"); System.out.println(user==user2); }
依赖注入概述
dao层和service层 impl
代码
package cn.cqie.dao.impl; import cn.cqie.dao.UserDAO; public class UserDAOImpl implements UserDAO { @Override public void save() { System.out.println("UserDAOImpl.save"); } }
package cn.cqie.service.impl; import cn.cqie.dao.UserDAO; import cn.cqie.pojo.User; import cn.cqie.service.UserService; public class UserServiceImpl implements UserService { private UserDAO userDAO; //setter注入 public void setUserDAO(UserDAO userDAO){ this.userDAO=userDAO; } public UserServiceImpl(){ } //构造器注入 public UserServiceImpl(UserDAO userDAO){ this.userDAO=userDAO; } @Override public void save() { System.out.println("UserServiceImpl.save"); userDAO.save(); } }
Setter注入
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- DI 依赖注入 UserDAO userDAO = new UserDAOImpl(); UserService userService = new UserServiceImpl(); 这时需要通过setter或者构造器注入 1、setter注入 --> <bean id="userDAO" class="cn.cqie.dao.impl.UserDAOImpl"/> <bean id="userService1" class="cn.cqie.service.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO"/> </bean> </beans>
@Test public void testSetterDI(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app4.xml"); UserService userService1 = (UserService) applicationContext.getBean("userService1"); userService1.save(); }
构造器注入
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 2、构造器注入 --> <bean id="userDAO2" class="cn.cqie.dao.impl.UserDAOImpl"/> <bean id="userService2" class="cn.cqie.service.impl.UserServiceImpl"> <constructor-arg name="userDAO" ref="userDAO2"/> </bean> </beans>
@Test public void testConstructorDI(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app4.xml"); UserServiceImpl userService2 = (UserServiceImpl) applicationContext.getBean("userService2"); userService2.save(); }
命名空间
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 命名空间注入 本质还是setter和构造器注入,只是换了种方式 --> <bean id="userDAO3" class="cn.cqie.dao.impl.UserDAOImpl"/> <bean id="userService3" class="cn.cqie.service.impl.UserServiceImpl" c:userDAO-ref="userDAO3" p:userDAO-ref="userDAO3"/> </beans>