什么是Spring?
高内聚低耦合的认识
Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
Spring的优势是什么?(敲黑板
1.低侵入式设计,代码污染极低
2.独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的承诺
3.Spring的DI机制降低了业务对象替换的复杂性,提高了组件之间的解耦
4.Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用
5.Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问
6.Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部
Spring重点的技术?
Spring中IOC和DI
Spring中AOP
Spring中Data Access
Spring的web应用
Spring和其他框架整合
Spring运行原理图
Spring特点
轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。它的底层设计模式采用了工厂模式,所有的 Bean 都需要注册到Bean工厂中,将其初始化和生命周期的监控交由工厂实现管理。程序员只需要按照规定的格式进行Bean开发,然后利用XML文件进行bean 的定义和参数配置,其他的动态生成和监控就不需要调用者完成,而是统一交给了平台进行管理。 [4] 控制反转是软件设计大师 Martin Fowler在 2004 年发表的”Inversion of Control Containers and the Dependency Injection pattern”提出的。这篇文章系统阐述了控制反转的思想,提出了控制反转有依赖查找和依赖注入实现方式。控制反转意味着在系统开发过程中,设计的类将交由容器去控制,而不是在类的内部去控制,类与类之间的关系将交由容器处理,一个类在需要调用另一个类时,只要调用另一个类在容器中注册的名字就可以得到这个类的实例,与传统的编程方式有了很大的不同,“不用你找,我来提供给你”,这就是控制反转的含义 [5] 。
面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。
ps:Sping官网 https://spring.io/(w3school也有可以有相关教材噶)
Ideal内利用Maven建一个有Spring框架的项目
(利用maven和前面搞过的一样 注意替换setting.xml以及那个java 和resources文件夹搞好)
1、在pom.xml中引入依赖 并且配置好tomcat~
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.15.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.15.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.15.RELEASE</version>
</dependency>
2、创建spring-config.xml
(这里要在rescues目录下 !这里搞错了导致报错Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [spring-config.xml]; nested exception is java.io.FileNotFoundException: class path resource [spring-config.xml] cannot be opened because it does not exist
其实存在的!只是目录搞错了QwQ)
右上角configure一下~
3、写几个函数来测试一下叭,引入一个写好的实例 尝试打印一下下
4、创建一个bean类和一个console控制类,console控制类编写一个基本的测试
package cn.edu.swun.test;
import cn.edu.swun.pojo.Emp;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain {
public static void main(String[] args){
得到emp对象
//Emp emp= new Emp();
//System.out.println(emp);
String[] xmlNameArray = {"spring-config.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(xmlNameArray);//容器
// 标准获取方式
Emp emp = context.getBean("emp",Emp.class);
// 另外一种获取方式
System.out.println(emp);
}
}
可以成功使用就算是Maven工程成功建立~
IOC控制反转和DI依赖注入
IOC:Inversion Of Control 控制反转,IOC:控制反转将程序员原来获取对象new实例化的方式转交给IOC来做,控制反转中的控制指的就是控制类的对象,而控制反转中的反转就是将实例化的操作转交给IOC来负责管理,它能实现最大的解耦。解耦指解除程序员和对象之间的关系,程序员实例化的操作交给IOC来负责。
总结:IOC控制反转创建对象,DI依赖注入来完成数据的封装,IOC是一种开发思想,DI是一种开发实现。
Spring中设置注入的方式
DI:依赖注入
1、通过构造函数注入:
无参构造函数注入 --- 默认
有参构造函数注入 --- 需要自己设置
<bean id="emp" class="cn.swun.edu.Emp">
<!--
name : 属性名称
value :赋值
type : 属性类型
index :参数索引位置(第几个参数位置)
-->
<constructor-arg index="0" type="int" value="123"></constructor-arg>
<!--<constructor-arg type="java.lang.String" value="FFDSS"></constructor-arg>-->
<constructor-arg type="double" value="1000"></constructor-arg>
</bean>
2、通过setter方式注入
在Spring-config.xml中加入bean,相当于取代了EmpServiceImpl中new的操作
<bean id="empService" class="cn.edu.swun.service.impl.EmpServiceImpl">
<property name="empDao" ref="empDaoImpl"></property>
</bean>
<bean id="empDaoImpl" class="cn.edu.swun.dao.impl.EmpDaoImpl"></bean>
对应的在service层generate一个setter
public class EmpServiceImpl implements EmpService {
private EmpDao empDao;
public void setEmpDao(EmpDao empDao) {
this.empDao = empDao;
}
public Emp queryEmp(){
System.out.println("====EmpServiceImpl======");
return empDao.queryEmp();
}
}
public class EmpDaoImpl implements EmpDao {
@Override
public Emp queryEmp() {
System.out.println("===EmpDaoImpl===");
return null;
}
}
搞一个测试类看一下,通过getBean对应活得刚刚写好的id是empService的bean,然后通过.class获取这个类,然后获得empService类型的接口,再调用其中的queryEmp()方法
public class TestMain {
public static void main(String[] args){
得到emp对象
//Emp emp= new Emp();
//System.out.println(emp);
String[] xmlNameArray = {"spring-config.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(xmlNameArray);//容器
// 标准获取方式
// Emp emp = context.getBean("emp",Emp.class);
// 另外一种获取方式
//System.out.println(emp.getEmp_id());
EmpService empService = context.getBean("empService", EmpServiceImpl.class);
empService.queryEmp();
}
}
3、p-namespace 命名空间的方式
为了简化property属性配置
注意:前提要将开始的命名空间配置为
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans<bean id="userServiceImpl" class="cn.edu.swun.service.impl.UserServiceImpl"
p:dao-ref="empDaoImpl"></bean>
<bean id="empDaoImpl" class="cn.edu.swun.dao.impl.UserDaoImpl"></bean>
4、List、Map、Set配置方式
<bean id="person" class="cn.edu.swun.pojo.Person">
<property name="id" value="1"></property>
<property name="personName" value="zhangsan"></property>
<property name="list">
<list>
<value>lists1</value>
<value>lists2</value>
<value>lists3</value>
</list>
</property>
<property name="set">
<set>
<value>212</value>
</set>
</property>
<property name="map">
<map>
<entry key="key01" value="01"></entry>
<entry key="key02" value="02"></entry>
</map>
</property>
</bean>
5、Properties配置方式
首先还是引入spring-config里面的上下文,context相关的xsi和文件
<?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">
<!-- 扫描jdbc.properties文件
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="locations" value="jdbc.properties"/>
</bean>
-->
<!-- 扫描上下文的配置文件jdbc.properties -->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<bean id="connection" class="cn.edu.swun.pojo.Connection">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
里面用到resources目录下新建的一个jdbc.properties(如果还有子目录可以用classpath),里面放置数据库的一写东西,有bean 的id 对应
(整合ssm数据的时候也会有用到)
connection.driver_class=com.mysql.jdbc.Driver
connection.url=jdbc:mysql://localhost:3306/gxa?useSSL=false
connection.username=root
connection.password=root1234
Bean Scope作用域的用法
1、Singleton:单例作用域,Spring初始化对象只有唯一一个------默认状态下(他们的输出值是一样的)
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu1 = ac.getBean("student", Student.class);
Student stu2 = ac.getBean("student", Student.class);
Student stu3 = ac.getBean("student", Student.class);
System.out.println(stu1.hashCode());
System.out.println(stu2.hashCode());
System.out.println(stu3.hashCode());
2、Prototype:原生作用域,每次调用Spring的getbean方法都会产生一个新的初始化对象
<bean id="student" class="com.gxa.pojo.Student" scope="prototype"></bean>
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu1 = ac.getBean("student", Student.class);
Student stu2 = ac.getBean("student", Student.class);
Student stu3 = ac.getBean("student", Student.class);
System.out.println(stu1.hashCode());
System.out.println(stu2.hashCode());
System.out.println(stu3.hashCode());
输出(每次都会分配不同的空间,他们是不同的值)
Spring中注解的配置方式
1、@Component组件
a.导入jar包:spring-aop-4.1.6.RELEASE.jar
b.配置文件spring-config.xml中配置扫描包
第一步配置中配置命名空间与schema 特别注意:
( xmlns:context="http://www.springframework.org/schema/context" 引入上下文
<context:component-scan base-package="cn.edu.swun.pojo"></context:component-scan> 扫描对应的目录)
<?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.edu.swun.pojo"></context:component-scan>
</beans>
在Emp实例中下面中加上@Component 有代替bean一样的效果,两个新的实例有相同的hushcode
(效果⬇️)
2、@Autowired
@autowired用于在对象的变量名、构造方法上实现自动装配
无须在配置文件中配置bean
无须使用setter注入方式 添加几个注解也可以完成功能,测试函数还是调用queryEmp
3、@Autowired(required=false)
在@Autowired中加入required=false那么当对象不存在的时候,不会出现错误异常。
4、@Qualifier
作用:为方法指定bean的名称,代替了构造方法的注入。
第一种:为方法指定bean的名称,每次调用都根据bean来实例化。
@Component
public class EmpServiceImpl {
@Autowired
@Qualifier("emp3")
private Emp emp;
@Autowired
@Qualifier("emp")
private Emp emp2;
@Autowired
@Qualifier("emp5")
private Emp emp3;
public void show(){
emp.queryEmp();
emp2.queryEmp();
emp3.queryEmp();
}
}
<bean id="emp3" class="cn.edu.swun.dao.impl.Storage"></bean>
<bean id="emp4" class="cn.edu.swun.dao.impl.Storage"></bean>
<bean id="emp5" class="cn.edu.swun.dao.impl.Storage"></bean>
第二种:通过构造方法的方式来注入
@Component
public class EmpServiceImpl2 {
private Emp2 emp2;
@Autowired
public EmpServiceImpl2(@Qualifier("stor") Emp2 emp2) {
super();
this.emp2 = emp2;
}
什么是AOP?
Aspect Oriented Programming 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要功能
日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要意图
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
作用:
1、面向切面编程从传统的面向过程完全转变,这种方式也主宰了软件世界。他是要求需求转化成一个一个的类,并且定义为数据成员。在面对一些复杂的关系的时候,用这种新的想法,新的思想去处理。
2、将需求功能从不相关的类中抽离出来,能够使很多类共享一个行为,这样的话如果发生改变就只修改次类就可以了,方便维护。
3、它是层次功能性,而不是嵌入式功能性,所以代码有较好的可读性和可维护性。
日志管理
权限管理
事物管理
AOP相关的概念
术语:
- 切面,Aspect:关注点---所有功能总称
- 连接点,join point:程序执行过程中的某一点
- 建议,Advice:AOP框架在特定的连接点上执行的动作
- 切入点,Pointcut:一系列连接点的集合
- 目标对象,Target Object:要被代理的对象
- AOP代理,AOP Proxy:AOP框架创建的对象,Spring中的AOP代理包含JDK动态代理和CGLIB代理,前者为接口代理(实现接口的目标代理),后者为类代理
- 引入,Introduction:简单说就是AOP中的方法
基于注解配置的AOP
AOP它也是面向接口编程
- 导入相关的jar包
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.8.13</version> </dependency>
- 编写接口与实现类
UserServiceImpl.java
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.gxa.aop.LogAop;
import com.gxa.dao.UserDao;
import com.gxa.service.UserService;
@Component("userSerivce")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
//切入点
@Override
public void findUserInfo() {
System.out.println("======service中执行=====");
userDao.findUserInfo();
}
@Override
public void findUser() {
userDao.findUserInfo();
}
@Override
public void findInfo(int id) {
userDao.findUserInfo();
}
}
AOP代理类LogAop.java
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* 用Spring创建AOP类
* 在创建AOP时应该加入@Aspect @Component
* AOP默认是面向接口的编程
* 在AOP中支持CGLIB方和JDK方式
* @author admin
*/
@Aspect
@Component
public class LogAop {
//配置通知(建议)
@Before("execution(* com.gxa.service.UserService.*(..))")
public void beforeAop(){
System.out.println("======在调用findUserInfo之前输出日志====");
}
@After("execution(* com.gxa.service.*.*(..))")
public void afterAop(){
System.out.println("======在调用findUserInfo之后输出日志====");
}
}
配置文件applicationContext.xml
注意:
1、先引入aop命名空间,和schema
2、再配置Aop的动态代理
<?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" xmlns:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.gxa.*"></context:component-scan> <aop:aspectj-autoproxy proxy-target-class=””></aop:aspectj-autoproxy> </beans> |
@Test
public void test01() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us = ac.getBean("userSerivce", UserService.class);
// us.findUserInfo();
// us.findUser();
us.findInfo(132);
}
运行结果:
基于配置xml配置文件的方式
applicationContext.xml的Aop配置
<?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" xmlns:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.gxa.*"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="myCut" class="com.gxa.aop.LogAopXml"></bean> <aop:config> <!-- 切面 --> <aop:aspect id="myAspect" ref="myCut"> <!-- 切入点 --> <aop:pointcut expression="execution(* com.gxa.service.*.*(..))" id="pointCut"/> <!-- 建议 --> <!-- 前置通知 --> <aop:before method="beforeAop" pointcut-ref="pointCut"></aop:before> <!-- 后置通知 --> <aop:after method="afterAop" pointcut-ref="pointCut"></aop:after> </aop:aspect> </aop:config> </beans> |
AOP的业务处理类LogAopXml.java
public class LogAopXml {
public void beforeAop(){
System.out.println("======在调用findUserInfo之前输出日志====");
}
public void afterAop(){
System.out.println("======在调用findUserInfo之后输出日志====");
}
}