Spring一览

概述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配置创建类的对象(反射:newInstance)


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");

效率很低,struts2 的 action是多例的,如果把创建ApplicationContext对象放到action对象中,每次都要重新加载,效率将会很低

spring初始化就是创建bean.xml中配置的bean对象,一般都是单例的,以后不用创建

解决思想:把加载配置文件和创建对象过程,在服务启动时完成(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>
spring注解
<!--开启注解扫描,到包里面扫面类,方法,属性上面是否有注解-->
<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*(..))

具体配置:

基于XML配置方式:

在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();
		//...
	}
}
使用注解:
@Aspect
public 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>(){
			@Override
			public 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");
		//sql
		String sql = "select * from user where id = ?";
		//预编译sql
		psmt = conn.prepareStatement(sql);
		//设置参数值
		psmt.setInteger(1,1);
		//执行sql
		rs = 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"/>
//第三步,在要使用事务的类上面添加注解
@Transactional
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值