一、什么是spring框架

  • spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。

二、架构概述

  2.1  IoC(Inversion of Control) :控制反转

  • 对象创建责任的反转,在spring中BeanFacotory是IoC容器的核心接口,负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。XmlBeanFacotory实现BeanFactory接口,通过获取xml配置文件数据,组成应用对象及对象间的依赖关系。

  • spring中有三种注入方式,一种是set注入,一种是接口注入,另一种是构造方法注入。

  2.1.1  第一个基于spring框架的程序(使用spring框架的ioc的优势)

  • 导包,由于本例是最简单的spring的程序,所以jar包比较少。

  • 创建spring的配置文件。

    spring.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"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <!-- 以上为头文件,必须在eclipse的xml catalog里有相应xsd文件, 有了头文件之后会有提示--> <bean class="test.Man" name="man"></bean> <!-- 创建test包里的Man类的对象,对象名为man -->
</beans>
  • Test.java
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext; public class Test { public static void main(String[] args) {
Test test=new Test(); test.one();
test.two();
test.three(); }
/**
* 普通模式:哪里需要对象,就在哪个方法里new 一个类的对象然后是用。
* 存在的不足:如果有很多个类都使用一个对象,而这个对象改变了的话,就需要在很多个类里修改这个对象。
*/
private void one() {
PersonI man=new Man();
man.eat();
man.sleep(); } /**
* 设计模式(工厂模式、门面模式):
* ,优势:如果PersonI的实现类修改了,只要在工厂PersonFactory中修改相应的类即可,而这里无须修改。
*/
private void two() {
PersonI woman=PersonFactory.getWomen(); //工厂模式 ,优势:如果PersonI的实现类修改了,只要在工厂PersonFactory中修改相应的类即可,而这里无须修改。
woman.eat();
woman.sleep(); } /**
* spring的ioc模式,将对象的实例化交给spring框架(spring容器)
*/
private void three() {
/**
* 这里的Man对象是在spring.xml中创建(new)好了
*/
// ApplicationContext applicationContext=new FileSystemXmlApplicationContext("src/spring.xml"); //推荐使用new ClassPathXmlApplicationContext
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
Man man=(Man)applicationContext.getBean("man"); //getBean("man")里的man是spring.xml文件里的id或者name为man的bean
man.sleep();
man.eat(); } }
  • PersonFactory.java
package test;

/**
* 工厂模式,
* @author Administrator
*
*/
public class PersonFactory {
public static PersonI getMan(){ PersonI man=new Man();
return man; } public static PersonI getWomen(){
PersonI women=new Women(); return women; }
}
  • PersonI.java
package test;

public interface PersonI {
void eat();
void sleep();
} class Man implements PersonI{ public void eat() {
System.out.println("Man 中的eat方法"); } public void sleep() {
System.out.println("Man 中的sleep方法"); } } class Women implements PersonI{ public void eat() {
System.out.println("Women 中的eat方法"); } public void sleep() {
System.out.println("Women 中的sleep方法"); }
}

结果:


 

  • 其中id和name标签属性都是bean的名称,区别在于id表示的bean如果这个xml被别的xml文件继承,则这个bean也可以在别的xml文件里使用。而name则不可以。
  • abstract="true" 表示这个bean是抽象的,不能实例化只能被继承。
  • parent="" 表示继承于某个类。
  • init-method="" 表示这个bean创建的时候就调用这个方法,当然这个方法的调用会在构造方法调用之后。 destroy-method="" 表示bean销毁的时候调用这个方法,有时候不会调用。
  • scope="singleton ||  prototype " singleton表示单例模式,对象只产生一个实例,init-method方法和destroy-method方法只执行一次。  prototype表示原型模式,每次产生一个对象,每次产生一个对象init-method方法和destroy-method方法都会执行一次。

2.2 DI:依赖注入 (三种)

  • 一种是set注入,一种是接口注入,另一种是构造方法注入。

    (1) set注入

这是最简单的注入方式,假设有一个SpringAction,类中需要实例化一个SpringDao对象,那么就可以定义一个private的SpringDao成员变量,
  然后创建SpringDao的set方法(这是ioc的注入入口):
随后编写spring的xml文件,<bean>中的name属性是class属性的一个别名,class属性指类的全名,因为在SpringAction中有一个公共属性Springdao,
所以要在<bean>标签中创建一个<property>标签指定SpringDao。<property>标签中的name就是SpringAction类中的SpringDao属性名,ref指下面<bean name="springDao"...>,
这样其实是spring将SpringDaoImpl对象实例化并且调用SpringAction的setSpringDao方法将SpringDao注入:

  (2) 构造器注入

这种方式的注入是指带有参数的构造函数注入,看下面的例子,我创建了两个成员变量SpringDao和User,但是并未设置对象的set方法,所以就不能支持第一种注入方式,

这里的注入方式是在SpringAction的构造函数中注入,也就是说在创建SpringAction对象时要将SpringDao和User两个参数值传进来:

    public class SpringAction {
//注入对象springDao
private SpringDao springDao;
private User user; public SpringAction(SpringDao springDao,User user){
this.springDao = springDao;
this.user = user;
System.out.println("构造方法调用springDao和user");
} public void save(){
user.setName("卡卡");
springDao.save(user);
}
}

在XML文件中同样不用<property>的形式,而是使用<constructor-arg>标签,ref属性同样指向其它<bean>标签的name属性:

    <!--配置bean,配置后该类由spring管理-->
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
<!--(2)创建构造器注入,如果主类有带参的构造方法则需添加此配置-->
<constructor-arg ref="springDao" index="0"></constructor-arg>
<constructor-arg ref="user" index="1"></constructor-arg>
</bean>
<bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
<bean name="user" class="com.bless.springdemo.vo.User"></bean>

  (3) 接口注入

  • Person.java
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Person { private Phone phone; /**
* set注入
* @param phone 接口
*/
public void setPhone(Phone phone) {
this.phone = phone;
} public void usePhone(){
this.phone.games(); } public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
Person person=(Person)context.getBean("person");
person.usePhone();
}
}
  • spring.xml
 xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <!-- 以上为头文件,必须在eclipse的xml catalog里有相应xsd文件, 有了头文件之后会有提示--> <bean name="person" class="test.Person">
<property name="phone" ref="huawei"></property>
</bean> <bean name="iPhone" class="test.iPhone"></bean>
<bean name="huawei" class="test.HuaWei"></bean> </beans>
  • Person类的成员属性Phone phone;是一个接口,在spring.xml实例化Person的时候,把Phone接口的实现类对象“huawei”引入到Person类中,如果要引用其他对象,只需要把ref="huawei" 即可,其他代码不用改变。

 2.3  AOP面向切面编程

aop就是纵向的编程,如下图所示,业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。

spring中面向切面变成的实现有两种方式,一种是动态代理,一种是CGLIB,动态代理必须要提供接口,而CGLIB实现是有继承。

  

  (1)AOP之代理模式(proxy模式)

  •     代理模式:通俗来讲,比如我们去买动车票,可以去动车站售票点买票,或者去代理点买票。通常来讲,售票点只提供售票而代理点不仅可以售票而且可以实现其他的功能。    从程序设计上讲,如果我们希望某个类不被直接使用,那么我们可以创建这个类的代理,代理并不真正实现功能,而是经过处理之后调用被代理类的功能,比如客户到代理点买票,代理点的票是从售票点买来的(相当于调用实现类的方法),可以得出:  代理应该实现一个接口(被代理类也实现这个接口),也有被代理类作为成员变量。
  •   静态代理 or 动态代理

    案例一: 静态代理

TicketIFC.java(售票接口)

package proxy;

public interface TicketIFC {

    void sellTicket();

}
Ticket_station.java(实现类)
package proxy;

public class Ticket_station implements TicketIFC{

    public void sellTicket() {
System.out.println("售票站售票");
} }
Ticket_proxy.java(代理类,实现售票接口且有实现类对象)
package proxy;

public class Ticket_proxy implements TicketIFC{

    private TicketIFC ticketIFC;

    public Ticket_proxy(TicketIFC ticketIFC){
this.ticketIFC=ticketIFC; } public void sellTicket() {
this.ticketIFC.sellTicket();
} }

Test.java(测试类)

package proxy;

public class Test {

    public static void main(String[] args) {

        TicketIFC ticketIFC=new Ticket_proxy(new Ticket_station());

        ticketIFC.sellTicket();

    }
}

结果:

  案例二:动态代理(代理类是在运行时动态产生的)

  • AOP的原理就是java的动态代理机制。
  • 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。
  • 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
  • 代理类原则: 1.实现某一接口  2.被代理的实现类。

PersonI.java (接口)

package spring_project_01;

public interface PersonI {

    void eat();
void sleep();
}

Man.java(实现类)

package spring_project_01;

public class Man implements PersonI{

    public void eat() {
System.out.println("Man中的eat方法"); } public void sleep() {
System.out.println("Man中的sleep方法"); } }

Women.java(实现类)

package spring_project_01;

public class Women implements PersonI{
public void eat() {
System.out.println("Women中的eat方法"); } public void sleep() {
System.out.println("Women中的sleep方法"); } }

ProxyUtil.java(代理类创建工具)

package proxy_dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态创建代理类
* @author Administrator
*
*/
public class ProxyUtil implements InvocationHandler{ private Object targetObj;
public Object createProxy(Object targetObj){
this.targetObj=targetObj;
//Proxy.newProxyInstance参数为被代理类的类加载器、被代理类的接口,以及一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
Object proxyObj=Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this); return proxyObj;
}
/**
* proxy:指代我们所代理的那个真实对象
* method:指代的是我们所要调用真实对象的某个方法的Method对象
* args:指代的是调用真实对象某个方法时接受的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("在被代理对象方法调用前会自动调用"); System.out.println("代理对象方法调用前");
Object objectReturnValue= method.invoke(this.targetObj, args); //在代理实例上处理方法调用并返回结果。java反射机制,即用方法调用对象。
System.out.println("代理对象方法调用后"); return objectReturnValue;
}
}

Test.java(测试类)

package proxy_static;

public class Test {

    public static void main(String[] args) {

        TicketIFC ticketIFC=new Ticket_proxy(new Ticket_station());

        ticketIFC.sellTicket();

    }
}

结果:


   案例三:模拟事务(实物的提交和回滚都不再dao层实现,而是采用代理模式实现)

1. 数据字典:

  2. RoleServiceI.java(接口)

package proxy_jdbc;

public interface RoleServiceI {

    void addRole() throws Exception;

}

  3. RoleServiceImpl.java(实现类,在动态代理模式下本类并不做事务的处理,把事务处理在代理类的invoke方法里处理)

package proxy_jdbc;

import java.sql.Connection;
import java.sql.Statement; public class RoleServiceImpl implements RoleServiceI{ public void addRole() throws Exception { Connection conn=null;
Statement stat=null;
StringBuffer SQL=new StringBuffer(); conn=DBUtil.getConn();
System.out.println("dao中的conn="+conn);
stat=conn.createStatement(); /**
* 插入到角色表
*/ SQL.setLength(0);
SQL.append("insert into role values(2,'管理员','管理员备注')");
stat.executeUpdate(SQL.toString()); /**
* 插入到用户表
*/ SQL.setLength(0);
SQL.append("insert into user values('111',11,'女')");
stat.executeUpdate(SQL.toString()); DBUtil.close(null, stat, null); //这里只关闭stat流,conn流在ServiceProxyUtil.invoke方法里统一关闭。 }
}

  4.  ServiceProxyUtil.java(动态代理生成工具):统一处理事务。

package proxy_jdbc;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException; /**
* 动态代理类创建工具
* @author Administrator
*
*/
public class ServiceProxyUtil implements InvocationHandler{ private Object targetObj; public Object createServiceProxy(Object targetObj){
this.targetObj=targetObj; Object proxy=Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this); return proxy;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 在本方法里对jdbc的事务进行处理和conn流的关闭,在dao层就不用再处理了。
*/
Object returnValue=null;
Connection conn=null;
try {
conn=DBUtil.getConn();
System.out.println("proxy中的conn="+conn);
conn.setAutoCommit(false); //禁止自动提交事务 returnValue=method.invoke(this.targetObj, args); //执行实现类方法 System.out.println("提交事务");
conn.commit(); } catch (Exception e) {
System.out.println("出现异常,回滚事务");
conn.rollback();
}finally{
DBUtil.close(conn, null, null);
}
return returnValue;
} }

  5. ServiceFactory.java(静态工厂)

package proxy_jdbc;
/**
* 静态工厂
* @author Administrator
*
*/
public class ServiceFactory {
public static RoleServiceI getRoleServiceImpl(){ RoleServiceI roleService=new RoleServiceImpl();
return roleService; }
}

  6. Test.java(测试类)

package proxy_jdbc;

public class Test {
public static void main(String[] args) {
//创建动态代理创建工具
ServiceProxyUtil proxyUtil=new ServiceProxyUtil(); //用动态代理创建工具创建出一个服务层的实现类,
RoleServiceI roleServiceImpl=(RoleServiceI)proxyUtil.createServiceProxy(ServiceFactory.getRoleServiceImpl()); try {
roleServiceImpl.addRole();
} catch (Exception e) {
e.printStackTrace();
} }
}

  7. DBUtil.java

package proxy_jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; public class DBUtil {
/**
* ThreadLocal本地线程,类似HttpSession操作,HttpSession针对每一个用户请求,而ThreadLocal针对每一个线程。
   * 这个对象用于实现当Connection创建之后除非关闭否则一直都是操作这个Connection对象
*/
private static ThreadLocal<Connection> local=new ThreadLocal<Connection>(); private static final String DRIVER="com.mysql.jdbc.Driver";
private static final String USER="root";
private static final String PASSWD="";
private static final String URL="jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8"; static{
try {
Class.forName(DRIVER);
} catch (Exception e) { throw new RuntimeException("无法加载驱动包");
} } public static Connection getConn(){
Connection conn=null;
try {
if(local.get() !=null){
//如果本地线程里有值,说明这个数据库连接被创建过,所以还是使用这个连接
conn=local.get();
}else{
//如果本地线程为空,则创建一个数据库连接。
conn= DriverManager.getConnection(URL,USER,PASSWD);
local.set(conn);
} } catch (SQLException e) {
e.printStackTrace();
} return conn;
} public static void close(Connection conn,Statement stat,ResultSet rs) throws Exception{
if(conn!=null && !conn.isClosed()){ if(local.get() !=null ){
local.remove();
}
conn.close();
}
if(stat!=null && !stat.isClosed()){
stat.close();
}
if(rs!=null && !rs.isClosed()){
rs.close();
}
} }

结果:

数据已插入。

(一)Spring框架基础的更多相关文章

  1. Spring框架基础2

    Spring框架基础2 测试Spring的AOP思想和注解的使用 导包(在前面的基础上添加) SpringAOP名词解释 AOP编程思想:横向重复代码,纵向抽取:就是说多个地方重复的代码可以抽取出来公 ...

  2. Spring学习指南-第二章-Spring框架基础(完)

    第二章 Spring框架基础 面向接口编程的设计方法 ​ 在上一章中,我们看到了一个依赖于其他类的POJO类包含了对其依赖项的具体类的引用.例如,FixedDepositController 类包含 ...

  3. 4-1 Spring框架基础知识

    Spring框架基础知识 1.Spring 框架作用 主要解决了创建对象和管理对象的问题. 自动装配机制 2.Spring 框架 (Spring容器,JavaBean容器,Bean容器,Spring容 ...

  4. Spring框架基础知识

    本人博客文章网址:https://www.peretang.com/basic-knowledge-of-spring-framework/ Spring框架简介 Spring , 一个开源的框架 , ...

  5. Spring框架基础

    1         Spring框架 1.1           Spring的基本概念 是一个轻量级的框架,提供基础的开发包,包括消息.web通讯.数据库.大数据.授权.手机应用.session管理 ...

  6. Spring 框架基础(04):AOP切面编程概念,几种实现方式演示

    本文源码:GitHub·点这里 || GitEE·点这里 一.AOP基础简介 1.切面编程简介 AOP全称:Aspect Oriented Programming,面向切面编程.通过预编译方式和运行期 ...

  7. Spring框架基础解析

    Spring是一个轻量级的.非侵入式的容器框架:对Bean对象的生命周期进行管理. Spring框架的核心:IOC(控制反转).DI(依赖注入).AOP(面向切面编程). (1) IOC:控制反转. ...

  8. Spring 框架基础(06):Mvc架构模式简介,执行流程详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.SpringMvc框架简介 1.Mvc设计理念 MVC是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集 ...

  9. Spring 框架基础(03):核心思想 IOC 说明,案例演示

    本文源码:GitHub·点这里 || GitEE·点这里 一.IOC控制反转 1.IOC容器思想 Java系统中对象耦合关系十分复杂,系统的各模块之间依赖,微服务模块之间的相互调用请求,都是这个道理. ...

  10. Spring 框架基础(02):Bean的生命周期,作用域,装配总结

    本文源码:GitHub·点这里 || GitEE·点这里 一.装配方式 Bean的概念:Spring框架管理的应用程序中,由Spring容器负责创建,装配,设置属性,进而管理整个生命周期的对象,称为B ...

随机推荐

  1. linux日常---3、linux常用操作

    linux日常---3.linux常用操作 一.总结 一句话总结: 状态的确是非常之好,享受这种状态. 1.linux删除文件夹和文件? rm -rf *:删文件和文件夹 rm -rf *.*:只能删 ...

  2. 有依赖的背包---P1064 金明的预算方案

    P1064 金明的预算方案 solution 1 暴搜 70pt dfs (当前搜到了第几个物品,产生的总价值,剩下多少钱) 剪枝 1:如果剩下的钱数<0,直接return就好,没必要继续了 剪 ...

  3. vuecli3集成easyui

    思路是这样的,首先要将jquery设置成全局,然后就可以正常使用easyUI了. jquery安装命令: npm install --save jquery jquery-easyui安装命令: np ...

  4. Android Studio 3.5新特性

    Android Studio 3.5新特性     原文链接:https://blog.csdn.net/jklwan/article/details/99974869 Android Studio ...

  5. 常用学习&面试资源网站

    https://github.com/MZCretin/RollToolsApi  开源通用API https://github.com/SenhLinsh/Android-Hot-Libraries ...

  6. RT-Thread代码启动过程——以及 $Sub$ $main 与 $Super$ $main

    [转]https://blog.csdn.net/yang1111111112/article/details/80913001 我们找到系统复位的地方,可以往下单步跟踪. ①从系统初始化开始执行,将 ...

  7. 一百三十九:CMS系统之首页帖子列表布局

    # 配置ueditor上传文件到七牛UEDITOR_UPLOAD_TO_QINIU = True # 设置为True是,视为开始把图片传到七牛储存,本地不储存UEDITOR_QINIU_ACCESS_ ...

  8. LVS搭建负载均衡集群(二)——DR模式

    (1).DR模式和TUN模式介绍 Direct Routing(直接路由):director分配请求到不同的real server.real server处理请求后直接回应给用户,这样director ...

  9. Django使用request和response对象

    当请求一张页面时,Django把请求的metadata数据包装成一个HttpRequest对象,然后Django加载合适的view方法,把这个HttpRequest 对象作为第一个参数传给view方法 ...

  10. transition css3 渐变效果

    div { width:100px; transition: width 2s; -moz-transition: width 2s; /* Firefox 4 */ -webkit-transiti ...