Spring一览

来源:互联网 发布:七夕表白网页源码 编辑:程序博客网 时间:2024/05/09 12:11
概述4.x
spring 开源轻量级框架(轻量级->依赖的东西少)
Spring是一站式框架:
spring在javaee三层结构中,每一层都提供了不同的解决技术

-web层:springMVC
-service: spring的ioc

-dao层:spring的jdbcTemplate


spring核心
1、aop:Aspect Oriented Programming 面向切面编程:扩展功能不修改源代码,相当于一个切面插入到源代码前面,或后面,环绕等
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码

需求:在添加用户的action中,添加写日志功能
纵向抽取机制:写一个父类,提供写日志功能,子类action调用(缺点:父类变动,子类也要变动)
aop:横向抽取机制:底层使用动态代码方式-

aop底层使用动态代理实现:
①、有接口情况,使用动态代理创建接口实现类代理对象

②、没有接口情况,使用动态代理创建类的子类代理对象(cglib)


ioc:控制反转
(个人理解:创建类对象,不需要new,而是通过配置的方法,注入进去)
比如一个类,我们需要调用其方法(非静态方法),需要new出类的对象,ioc指不需要new出对象
而是交给spring配置创建类的对象


IOC、DI 区别:
IOC:控制反转,把对象创建交给spring进行配置
DI : 依赖注入,向类里面的属性中设置值
关系:依赖注入不能单独存在,需要在IOC的基础上完成操作


ioc底层原理:
工厂模式解耦合操作:

public class SpringFactory{public static UserService getUserService(){return new UserService();   //写死了,任然耦合}}//这样和工厂类耦合public class UserServlet{UserService s = SpringFactory.getUserService();}
ioc做法:
使用xml配置文件:

<bean id="userService" class="net.dhh.service.UserService"/>
//Spring工厂类:public static Object getUserService(){//dom4j + 反射Class clazz = Class.forName(className);return clazz.newInstance();}

bean实例化的三种方式

1、使用类的无参构造函数创建(实际项目用的就是这种方式)
<bean id = "User" class="net.dhh.bean.User"/>
如果User类没有提供无参构造方法,将会抛出异常!

2、使用静态工厂创建

public class BeanFactory{//静态方法public static User getUser(){return new User();}}
<bean id="user" class="net.dhh.bean.BeanFactory" factory-method="getUser"/>

3、通过实例工厂创建:
public class BeanFactory{//静态方法public User getUser(){return new User();}}
<bean id="beanFactory" class="net.dhh.bean.BeanFactory"/><bean id="user" factory-bean="beanFactory" factory-method="getUser"/>

bean标签的scope属性:
singleton:   默认值,单例(重点)--> context.getBean("user") == context.getBean("user");
prototype:   多例(重点)--> context.getBean("user") != context.getBean("user") 
     -->struts2的action为多例的,要配置这个属性
     -->想起多年前项目的一个bug,两个不同的request请求到struts2的action,由于
     -->action没有配置多例,导致了两个request请求的数据混用

request:     web项目中,spring创建一个bean对象,将对象存入到request域中
session:     web项目中,spring创建一个bean对象,将对象存入到session域中
globalSession : 全局session-->替代品为redis--->单点登录功能


属性注入:

<!--1、使用有参构造注入属性--><bean id="demo" class="net.dhh.test.Demo"><constructor-arg name="username" value="xxx"></constructor></bean><!--2、使用set方法注入属性--><bean id="demo" class="net.dhh.test.Demo"><!--注入的属性是字符串--><property name="username" value="xxx"></property></bean><!--3、注入对象--><bean id="userDao" class="xxx.xxx.xx"></bean><bean id="userService class="xx.xx.xx"><property name="userDao ref="userDao"></property></bean><!--4、名称空间注入(了解)--><!--xmlns:p="http://www.srpingframework.org/schema/p" --><bean id="demo" class="net.dhh.test.Demo" p:username="xxx"></bean><!--可以注入属性名为username的属性值--><!--5、属性注入复杂类型:数组,list, map ,properties --><bean id="demo" class="net.dhh.test.Demo"><!--注入的属性是数组或者list--><property name="arrs"><list><value>1<alue><value>2<alue><value>3<alue></list></property><!--注入的属性是map--><property name="mymap"><map><entry key="aa" value="lucy"></entry><entry key="bb" value="tom"></entry></map></property><!--注入的属性properties -><property name="myprop"><props><prop key="driverclass">com.mysql.jdbc.Driver</prop><prop key="username">root</prop></props></property></bean>
Spring初始化:
ApplicationContext context = new ClassPathXmlApplication("bean.xml");
效率很低,action是多例的,如果把创建ApplicationContext对象放到action对象中,每次都要重新加载,效率将会很低


解决思想:把加载配置文件和创建对象过程,在服务启动时完成(spring已经做了,开发者只需配置)

实现原理:在服务器启动时,会为每一个项目创建ServletContext对象
在ServletContext对象创建时,使用监听器(ServletContextListener)可以具体监听到ServletContext对象在什么时候创建,
在ServletContext对象创建时,加载Spring配置文件,解析配置文件并创建里面的bean对象
把创建的bean对象放到ServletContext中(setAttribute)
在获取对象的时候,从ServletContext中拿(getAttribute)

spring配置文件的加载:
1、服务器启动时,创建对象加载配置文件
2、底层使用监听器,ServletContext对象

spring做了封装,封装了一个监听器,只需要配置监听器就可以实现spring配置文件的加载

<!-- 配置监听器--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--指定spring配置文件位置--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:net/dhh/applicationContext.xml</param-value></context-param>
注解
<!--开启注解扫描,到包里面扫面类,方法,属性上面是否有注解-->
<context:component-scan base-package="com.clou.douliu.server.mybatis.mapper" /><!--如果是几个,可以逗号相隔,如果他们在同一个父包里面,也可以只写父包的包名--><!--只会扫描属性上面的注解,建议开启上面一个配置就行了,上面那个包含所有--><context:annotation-config />
@Component(value="user")   //作用在类上,相当于配置:<bean id ="user" class=""></bean>public class User{
Spring中提供@Component的三个衍生注解(功能到目前是一样的,截止到2017-02-06,spring4)
@Controller  : web层
@Service     : 业务层
@respository : 持久层

这4个注解的功能都是一样的,这种做法是为了将来考虑,可能今后的版本,spring会对不同的分层做不同的优化
,现在建议web层使用@controller,业务层使用@Service,这会使类的分层更加清晰。


使用注解来创建对象:区分单例还是多例

//使用注解来创建对象:区分单例还是多例@Service(value="user")@Scope(value="prototype")   //如果是Struts2的action,就一定是用多例public class User{

属性注入的注解:(使用注解,属性就不需要提供set方法了)
@Autowired 和 @Resource 
1、都可以完成对象注入

@Autowired private UserDao userDao; //Autowired 是根据类名来注入,也就是value值可以随便取,使用Autowired都不受影响@respository(value="UserDao")public class UserDao{@Resource(name="userDao")private UserDao userDao;//Resource就是通过指定bean id的名字来注入对象,如果@respository(value="UserDao2")public class UserDao{//这样,Resource将注入不进来,会抛出异常


spring专业术语:
public class UserService{public void add(){};public void update(){};public void delete(){};public void findAll(){};}
连接点:类里面哪些方法可以被增强(加功能),这些方法称为连接点,add,update,delete,findAll都可以增强,都是连接点
切入点:在类里面有很多方法都可以被增强,但实际上我们可能只增强了add,update方法,实际增强的方法称为切入点
通知/增强(Advice): 增强的逻辑,称做Advice,比如要在add中加入写日志的功能,写日志的功能,称为Advice(通知/增强)
前置通知:在方法之前执行(*)
后置通知:在方法之后执行(*)
异常通知:方法出现异常执行
最终通知:在后置之后执行
环绕通知:在方法之前和之后执行(*)
切面:把Advice应用到具体的方法上面,过程称为切面(把增强应用到切入点的过程)

spring的aop操作:
1、在spring中进行aop操作,使用aspectj实现
①aspectj不是spring的一部分,和spring一起使用进行aop操作。
②spring2.0以后新增了对Aspectj的支持


2、使用Aspectj实现aop有两种方式
①基于aspectj的xml配置(配置很复杂,常使用注解的方式)
②基于aspectj的注解方式

使用表达式配置切入点(要被增强的方法称为切入点)
常用的表达式:
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

访问修饰符--->public private protected ,*代表所有
?--->问号代表的是一个空格
方法名--->指要被增强的方法名,要把包名和类名都带上
参数--->指要被增强的方法的参数,..代表所有的情况

①execution(* net.dhh.service.UserService.add(..))②execution(* net.dhh.service.UserService.*(..))      //代表UserService下所有的方法③execution(* *.*(..))    //all of it ④execution(* save*(..))    //匹配所有save开头的方法,没验证过,可能是execution(* *.save*(..))

具体配置:
在UserService的所有方法中加入写日志的功能:

<bean id="userService" class="net.dhh.service.UserService"></bean><bean id="logManager" class="net.dhh.util.LogManager"></bean>
<!--配置aop操作--><aop:config><!--配置切入点(要增强的方法)--><aop:pointcut expression="execution(* net.dhh.service.UserService.*(..))" id="pointcut1" /><!--配置切面(把增强应用到切入点的过程)--><aop:aspect ref="logManager"><!--配置Advice(增强)类型--><!--1、增强方法在切入点之前调用--><aop:before method="writeLog" pointcut-ref="pointcut1"/>  <!--writeLog为LogManager写日志的方法--><!--2、增强方法在切入点之后调用--><aop:after-returning method="writeLog" pointcut-ref="pointcut1"/>  <!--3、增强方法环绕切入点--><aop:around method="writeLog2" pointcut-ref="pointcut1"/>  </aop:aspect></aop:config>
public class LogManager{public void writeLog(){//....}//注意:环绕的写法public void writeLog2(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{//....//执行要被增强的方法proceedingJoinPoint.proceed();//...}}
使用注解:
@Aspectpublic class LogManager{//在方法上面使用注解完成增强配置@Before(value="execution(* net.dhh.service.UserService.*(..))")public void writeLog(){//....}}
配置打开注解:
<!--开启aop操作--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>

个人理解:
aop:把一个方法增强,而不改源代码
增强的方法 -- >增强/Advice  -->LogManager.writeLog();
被增强的方法--> 切入点 -- > UserService.*();
把增强加到被增强的方法-->方面


JdbcTemplate:
ORM持久化技术    Spring模板类
JDBC org.springframework.jdbc.core.JdbcTemplate
Hibernate5.0    org.springframework.orm.hibernate5.HibernateTemplate(spring对hibernate框架进行了封装)
MyBatis org.springframework.orm.ibatis.SqlMapClientTemplate

jdbcTemplate对jdbc进行封装,用法和dbUtils相似,对数据进行crud操作。

public void testJdbcTemplate(){//spring提供的数据源配置DriverManagerDataResource dataSource = new DriverManagerDataResource();dataResource.setDriverClassName("com.mysql.jdbc.Driver");dataResource.setUrl("jdbc:mysql://databaseName");dataResource.setUsername("root");dataResource.setPassword("root");//创建JdbcTemplate对象,设置数据源JdbcTemplate jdbcTemplate = new JdbcTemplate(dataResource);String sql = "insert into user value(?,?)";//增删改都是用update, 后面参数类型Object...int row = jdbcTemplate.update(sql,"aaa","123"); //得到一个值//sql = "select * from user";//int count = jdbcTemplate.queryForObject(sql,Integer.class);//查询sql = "select * from user where id =?";User user = jdbcTemplate.queryForObject(sql,new RowMapper<User>(){@Overridepublic User mapRow(Result rs ,int rowNum) throws SQLExeception{User u = new User();u.setId(rs.getInt("id"));u.setUsername(rs.getString("username"));return u;}},1);}
JDBC写法:

//JDBC写法:public void testJDBC(){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;try{Class.forName("com.mysql.jdbc.Driver");//创建连接conn = DriverManager.getConnection("jdbc:mysql:///databaseName","root","root");//sqlString sql = "select * from user where id = ?";//预编译sqlpsmt = conn.prepareStatement(sql);//设置参数值psmt.setInteger(1,1);//执行sqlrs = psmt.executeQuery();//遍历while(rs.next()){String username = rs.getString("username");String password = rs.getString("password");}}catch(Exception){}finally{try{rs.close();psmt.close();conn.close();}catch(Exception e){}}}
配置C3P0,编码写法:
ComboPooledDataResource dataResource = new ComboPooledDataResource();dataResource.setDriverClass("com.mysql.jdbc.Driver");dataResource.setJdbcUrl("jdbc://mysql:///databaseName");dataResource.setUser("root");dataResource.setPassword("root");
spring配置c3p0数据源:
<bean id ="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!--注入属性值--><property name="driverClass" value="com.mysql.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc://mysql:///databaseName"></property><property name="user" value="root"></property><property name="password" value="root"></property></bean>
jdbcTemplate使用:
<bean id="userService" class="net.dhh.service.UserService"><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="net.dhh.dao.UserDao"><property name="jdbcTemplate" ref="jdbcTemplate"></property></bean><!--创建jdbcTemplate对象--><bean id ="jdbcTemplate" class="org.springframework.jdbc.JdbcTemplate"><!把数据源注入进来--><property name="dataSource" ref="dataSource"></property></bean>

Spring事物管理:
spring事物管理两种方式:
第一种:编程事物管理(不同)
第二种:声明式事物管理

①基于xml配置文件实现

<!--第一步,配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"></property></bean><!--第二步,配置事务增强--><tx:advice id="txadvice" transation-manager="transactionManager"><tx:attributes><!--设置进行事务操作的方法匹配规则--><!--给insert开头的方法都加上事务管理--><!--虽然使用注解的方式配置事务比较简单,但这种方式可以规范开发的方法名--><tx:method name="insert*" propagation="REQUIRED"/><tx:method name="delete*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="save*" propagation="REQUIRED"/><tx:method name="find*" propagation="SUPPORTS" read-only="true"/><tx:method name="get*" propagation="SUPPORTS" read-only="true"/><tx:method name="select*" propagation="SUPPORTS" read-only="true"/></tx:attributes></tx:advice><!--第三步,配置切面--><aop:config><!--切入点--><!--service所有实现类的所有方法--><aop:pointcut expression="execution(* net.dhh.service.impl.*.*(..))" id="pointcut1"/><!--切面--><aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/></aop:config>

②基于注解实现

<!--第一步,配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"></property></bean><!--第二步,开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"/>
//第三步,在要使用事务的类上面添加注解@Transactionalpublic class OrderService{}

Spring事务管理器:
Spring为不同的持久化框架提供了不同PlatformTransactionManager(事物管理器)接口实现
1、针对spring jdbc或ibatis进行持久化数据的实现类
org.springframework.jdbc.datasource.DataSourceTransactionManager  

2、针对Hibernate5.0版本进行持久化数据的实现类
org.springframework.orm.hibernate5.HibernateTransactionManager


事物的四种隔离级别:
default  使用后端数据库默认的隔离级别
read_uncommited  允许你读取还未提交的改变了的数据,可能导致脏读,幻读,不可重复读
read_commited 允许在并发事务已经提交后读取,可防止脏读,但幻读,不可重复读仍然发生
repeatable_read 对相同字段的多次读取是一致的,除非数据被事务本身改变,可防止脏读,不可重复读,但幻读仍可能发生
serialiazable 完全俯冲acid的隔离级别,确保不发生脏读,幻读,不可重复读。在所有的隔离级别是最慢的.他是典型的通过
锁定在事务中设计的数据表来完成的


0 0
原创粉丝点击