(一)Spring框架基础
一、什么是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注入
(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框架之动态代理
(一)Spring框架基础的更多相关文章
- Spring框架基础2
Spring框架基础2 测试Spring的AOP思想和注解的使用 导包(在前面的基础上添加) SpringAOP名词解释 AOP编程思想:横向重复代码,纵向抽取:就是说多个地方重复的代码可以抽取出来公 ...
- Spring学习指南-第二章-Spring框架基础(完)
第二章 Spring框架基础 面向接口编程的设计方法 在上一章中,我们看到了一个依赖于其他类的POJO类包含了对其依赖项的具体类的引用.例如,FixedDepositController 类包含 ...
- 4-1 Spring框架基础知识
Spring框架基础知识 1.Spring 框架作用 主要解决了创建对象和管理对象的问题. 自动装配机制 2.Spring 框架 (Spring容器,JavaBean容器,Bean容器,Spring容 ...
- Spring框架基础知识
本人博客文章网址:https://www.peretang.com/basic-knowledge-of-spring-framework/ Spring框架简介 Spring , 一个开源的框架 , ...
- Spring框架基础
1 Spring框架 1.1 Spring的基本概念 是一个轻量级的框架,提供基础的开发包,包括消息.web通讯.数据库.大数据.授权.手机应用.session管理 ...
- Spring 框架基础(04):AOP切面编程概念,几种实现方式演示
本文源码:GitHub·点这里 || GitEE·点这里 一.AOP基础简介 1.切面编程简介 AOP全称:Aspect Oriented Programming,面向切面编程.通过预编译方式和运行期 ...
- Spring框架基础解析
Spring是一个轻量级的.非侵入式的容器框架:对Bean对象的生命周期进行管理. Spring框架的核心:IOC(控制反转).DI(依赖注入).AOP(面向切面编程). (1) IOC:控制反转. ...
- Spring 框架基础(06):Mvc架构模式简介,执行流程详解
本文源码:GitHub·点这里 || GitEE·点这里 一.SpringMvc框架简介 1.Mvc设计理念 MVC是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集 ...
- Spring 框架基础(03):核心思想 IOC 说明,案例演示
本文源码:GitHub·点这里 || GitEE·点这里 一.IOC控制反转 1.IOC容器思想 Java系统中对象耦合关系十分复杂,系统的各模块之间依赖,微服务模块之间的相互调用请求,都是这个道理. ...
- Spring 框架基础(02):Bean的生命周期,作用域,装配总结
本文源码:GitHub·点这里 || GitEE·点这里 一.装配方式 Bean的概念:Spring框架管理的应用程序中,由Spring容器负责创建,装配,设置属性,进而管理整个生命周期的对象,称为B ...
随机推荐
- linux日常---3、linux常用操作
linux日常---3.linux常用操作 一.总结 一句话总结: 状态的确是非常之好,享受这种状态. 1.linux删除文件夹和文件? rm -rf *:删文件和文件夹 rm -rf *.*:只能删 ...
- 有依赖的背包---P1064 金明的预算方案
P1064 金明的预算方案 solution 1 暴搜 70pt dfs (当前搜到了第几个物品,产生的总价值,剩下多少钱) 剪枝 1:如果剩下的钱数<0,直接return就好,没必要继续了 剪 ...
- vuecli3集成easyui
思路是这样的,首先要将jquery设置成全局,然后就可以正常使用easyUI了. jquery安装命令: npm install --save jquery jquery-easyui安装命令: np ...
- Android Studio 3.5新特性
Android Studio 3.5新特性 原文链接:https://blog.csdn.net/jklwan/article/details/99974869 Android Studio ...
- 常用学习&面试资源网站
https://github.com/MZCretin/RollToolsApi 开源通用API https://github.com/SenhLinsh/Android-Hot-Libraries ...
- RT-Thread代码启动过程——以及 $Sub$ $main 与 $Super$ $main
[转]https://blog.csdn.net/yang1111111112/article/details/80913001 我们找到系统复位的地方,可以往下单步跟踪. ①从系统初始化开始执行,将 ...
- 一百三十九:CMS系统之首页帖子列表布局
# 配置ueditor上传文件到七牛UEDITOR_UPLOAD_TO_QINIU = True # 设置为True是,视为开始把图片传到七牛储存,本地不储存UEDITOR_QINIU_ACCESS_ ...
- LVS搭建负载均衡集群(二)——DR模式
(1).DR模式和TUN模式介绍 Direct Routing(直接路由):director分配请求到不同的real server.real server处理请求后直接回应给用户,这样director ...
- Django使用request和response对象
当请求一张页面时,Django把请求的metadata数据包装成一个HttpRequest对象,然后Django加载合适的view方法,把这个HttpRequest 对象作为第一个参数传给view方法 ...
- transition css3 渐变效果
div { width:100px; transition: width 2s; -moz-transition: width 2s; /* Firefox 4 */ -webkit-transiti ...