【JAVA高级学习】Spring4【2】

本文详细探讨了Spring4中的代理设计模式,包括静态代理和动态代理,特别是JDK与CGLIB的实现。接着,介绍了Spring的自动注入特性,如何加载properties文件,以及scope属性在不同场景下的应用。此外,文章还讲解了单例设计模式的懒汉式和饿汉式实现,并重点阐述了声明式事务及其<tx:method>标签的配置。最后,回顾了Ajax的基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理设计模式

1. 设计模式:前人总结的一套解决特定问题的代码。
2. 代理设计模式的优点:
	2.1 保护真实对象
	2.2 让真实对象职责更明确
	2.3 扩展
3. 代理设计模式:
	3.1 真实对象(老总)
	3.2 代理对象(秘书)
	3.3 抽象对象(抽象功能:制定小目标)

静态代理设计模式

1. 由代理对象代理所有真实对象的功能
	1.1 自己编写代理类
	1.2 每个代理的功能需要单独编写
2. 静态代理模式的缺点:
	2.1 当代理功能比较多时,代理类中方法,也需要写很多。
3. 实现步骤:
	3.1 接口-抽象对象
public interface Goneng {
	void zhidingxiaomubiao();
	void chifan();
}
	3.2 真实对象
public class Laozong implements Goneng{
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void zhidingxiaomubiao() {
		System.out.println("制定小目标");
	}
	public Laozong() {
		super();
	}
	public Laozong(String name) {
		super();
		this.name = name;
	}
	
	@Override
	public void chifan() {
		System.out.println("吃饭");
	}
}
	3.3 代理对象
public class Mishu implements Goneng{
	private Laozong laozong=new Laozong("云云");
	
	@Override
	public void zhidingxiaomubiao() {
		System.out.println("约定时间");
		laozong.zhidingxiaomubiao();
		System.out.println("把访客信息备注");
	}
	
	@Override
	public void chifan() {
		System.out.println("约定时间");
		laozong.chifan();
		System.out.println("把访客信息备注");
	}
}
	3.4 测试类
public class Women {
	public static void main(String[] args) {
		Mishu mishu=new Mishu();
		mishu.zhidingxiaomubiao();
	}
}

动态代理

1. 为了解决静态代理中的频繁编写代理功能方法的缺点
2. 分类:
	2.1 JDK提供的
	2.2 cglib动态代理

JDK动态代理

1. 和cglib动态代理优点:
	1.1 优点:JDK自带不需要额外导入jar包
	1.2 缺点:
		1.2.1 真实对象必须实现接口
		1.2.2 利用反射机制,效率不高
2. 实现步骤:
	2.1 接口-抽象方法
public interface Gongneng {
	void chifan();
	void mubiao();
}
		2.2 真实对象
public class Laozong implements Gongneng{
	@Override
	public void chifan() {
		System.out.println("吃饭");
	}
	@Override
	public void mubiao() {
		System.out.println("目标");
	}
}
	2.3 代理对象
public class Mishu implements InvocationHandler{
	private Laozong laozong=new Laozong();
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("预约时间");
		Object result = method.invoke(laozong, args);
		System.out.println("记录访客信息");
		return result;
	}
}

	2.4 测试类
public class Women {
	public static void main(String[] args) {
		Mishu mishu=new Mishu();
		//第一个参数:反射时使用的类加载器
		//第二个参数:Proxy需要实现的接口
		//第三个参数:通过接口对象调方式时,需要调用哪个类的invoke方法
		Gongneng gongneng = (Gongneng) Proxy.newProxyInstance(Women.class.getClassLoader(), new Class[] {Gongneng.class}, mishu);
		gongneng.chifan();
	}
}

cglib动态代理

1. cglib优点:
	1.1 基于字节码:生成真实对象的一个子类
		1.1.1 运行效率高于jdk动态代理
	1.2 不需要实现接口
2. cglib缺点:
	2.1 非jdk功能, 需要额外导入jar
3. 使用Spring aop时,只要出现Proxy和真实对象转换异常
	3.1 设置为true:使用cglib
	3.2 设置为false:使用jdk(默认值)
<!-- proxy-target-class:true使用cglib动态代理(注解基于此方式),false使用jdk动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
4. 实现步骤:
	4.1 真实对象
public class Laozong{
	public void chifan() {
		System.out.println("吃饭");
	}
	public void mubiao() {
		System.out.println("目标");
	}
}
	4.2 处理对象
public class Mishu implements MethodInterceptor{
	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
		//arg0 生成的子类对象
		//arg1 代理的方法
		//arg2 参数
		//arg3 子类生成的代理方法
		
		System.out.println("预约时间");
//		Object result = arg1.invoke(arg0, arg2);
		Object result = arg3.invokeSuper(arg0, arg2);
		//死循环,arg3代理类对象
//		Object result = arg3.invoke(arg0, arg2);
		System.out.println("备注");
		return result;
	}
}
	4.3 测试类
public class Women {
	public static void main(String[] args) {
		Mishu mishu=new Mishu();
		Enhancer enhancer=new Enhancer();
		enhancer.setSuperclass(Laozong.class);
		enhancer.setCallback(mishu);
		
		Laozong laozong = (Laozong) enhancer.create();
		laozong.chifan();
	}
}

自动注入

1. 在Spring配置文件中:对象名(id="")与引用名(ref="")相同,可以使用自动注入,可以不配置<property>(通过注解的方式,自动注入无效)
2. 两种配置方式:
	2.1 在<bean>中通过autowire=""属性配置,只针对该bean生效
	2.2 在<beans>中通过default-autowire=“”属性配置,全局生效(当前文件中所有bean按照该配置)
3. autowire=""可取值:
	3.1 default:默认值,根据全局default-autowire=“”值,默认全局和局部都未配置的情况下,相当于:no
	3.2 no:不自动注入
	3.3 byName:通过名称自动注入。在Spring容器中(ApplicationContext)找类的id(注解或xxxMapper.java等类的bean不在配置文件中出现),若存在多个则报错
	3.4 byType:通过类型自动注入。在Spring容器中,不可以出现两个相同类型的bean,否则报异常
	3.5 constructor:通过构造方法
		3.5.1 提供对应参数的构造方法(构造方法中包含注入的那个对象)
		3.5.1 底层先使用byType,若存在多个,则通过byName

Spring中加载properties文件

1. 在src下新建:xxxx.properties文件
2. 在spring配置文件中:先引入xmlns:context,再添加配置如下:
	2.1 如果需要加载多个配置文件,使用","分割
<context:property-placeholder location="classpath:db.properties" />
3. 添加了属性文件加载,并且在<beans>中开启了自动注入,需要注意:
  	3.0 自动注入的优先级比较高,会先实例化有引用对象的类,而不管其是否能够自动注入成功;而此时properties文件尚未加载,若在实例化的过程中使用到properties文件的参数,则会出异常
	3.1 SqlSessionFactory的id不能叫做:sqlSessionFactory,因为:org.mybatis.spring.mapper.MapperScannerConfigurer有同名属性,会自动注入
	3.2 修改org.mybatis.spring.mapper.MapperScannerConfigurer类,将属性名:sqlSessionFactory换成sqlSessionFactoryBeanName
		3.2.1 原来通过ref引用替换成value,自动注入只能影响ref,不会影响value
<!-- 扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="com.sxt.mapper"></property>
	<!-- <property name="sqlSessionFactory" ref="factory"></property> -->
	<property name="sqlSessionFactoryBeanName" value="factory"></property>
</bean>
4. 在被Spring管理的类中:通过@value("${参数键名}"),取出properties中的内容
	4.1 需要添加注解扫描
<context:component-scan base-package="com.sxt.service.impl"></context:component-scan>
	4.2 在类中添加
		4.2.1 参数键名 和 变量名可以不相同
		4.2.2 变量类型任意,只要保证:参数键名对应的值能转换成这个类型。
@Value("${my.demo}")
private String test;

scope属性

1. <bean>标签的属性
2. 作用:控制对象有效范围(单例 ,多例等)
3. <bean>标签对应的对象:默认是单例的
	3.1 无论获取多少次,都是同一个对象
4. scope可取值:
	4.1 默认值:singleton,单例
	4.2 prototype:多例,每次调用重新实例化
	4.3 request:每次请求重新实例化
	4.4 session:每个会话对象内,对象是单例的
	4.5 application:application对象内,对象是单例的
	4.6 global session:spring推出的一个对象,依赖于:spring-webmvc-portlet-4.1.6.RELEASE.jar。类似于session

单例设计模式

1. 作用:在应用程序中最多只能有一个实例
2. 好处:
	2.1 提升运行效率
	2.2 实现数据共享。案例:application对象

懒汉式

1. 对象只有被调用时才去创建
2. 实例代码:
public class SingleTon {
	//4.由于静态方法需要调用,所以添加成staitc,并设置为private避免直接调用
	private static SingleTon singleton;
	
	//1.私有化构造方法,统一由入口方法创建,并控制
	private SingleTon() {
	}
	
	//2.入口方法,需加上static,从而不需要通过对象调用
	//3.需要引入全局变量,判断是否已经实例化
	public static SingleTon getInstance() {
		//5.判断是否为空不为空,则创建
		if(singleton==null) {
			//6.多线程环境下,if可能多个线程同时成立,故需要加锁
			synchronized (SingleTon.class) {
				//7.双重检测锁,第一个线程拿到锁创建完成之后,避免第二个线程拿到锁,重新创建。
				if(singleton==null) {
					singleton= new SingleTon();
				}
			}
		}
		return singleton;
	}
}
3. 由于添加了锁,会导致效率低

饿汉式

1. 解决了懒汉式中多线程访问可能出现同一个对象和效率低的问题。
2. 实例代码:
public class SingleTon {
	//在类加载时进行实例化,天然的线程安全
	private static SingleTon singleton=new SingleTon();
	private SingleTon() {
	}
	public static SingleTon getInstance() {
		return singleton;
	}
}

声明式事务

1. 编程式事务
	1.1 由程序员编写事务控制代码
	1.2 例如:OpenSessionInView编程式事务
2. 声明式事务
	2.1 事务控制代码已经由spring写好,程序员只需要声明出哪些方法需要进行事务控制和如何进行事务控制
3. 声明式事务都是针对于ServiceImpl类下方法的。
4. 事务管理器是基于通知(advice)的。
5. 在spring配置文件中配置声明式事务:
	5.1 事务是基于通知的,所以必须配置切点
	5.2 事务需要将数据提交数据库,所以必须要有dataSource
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" 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>
 <!-- 配置声明式事务 -->
 <!-- spring-jdbc.jar中 -->
 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 	<property name="dataSource" ref="dataSource"></property>
 </bean>
 <tx:advice id="txAdvice" transaction-manager="txManager">
 	<tx:attributes>
 		<!-- 哪些方法需要事务控制 -->
 		<!-- 方法以ins开头的都需要事务管理 -->
 		<tx:method name="ins*" />
 		<tx:method name="del*" />
 		<tx:method name="upd*" />
 		<tx:method name="*" read-only="true"/>
 	</tx:attributes>
 </tx:advice>
 <aop:config>
 	<!-- 切点范围设置大一点 -->
 	<aop:pointcut expression="execution(* com.sxt.service.impl.*.*(..))" id="mypoint"/>
 	<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"/>
 </aop:config>

声明式事务中(<tx:method>标签)属性解释

1. name="":表示哪些方法需要有事务控制,支持*通配符
2. read-only="true|false":表示是否是只读事务
	2.1 true:告诉数据库此事务是只读事务。属于数据库优化,会对性能有一定提升,所以只要是查询方法,建议使用此属性。
	2.2 false:默认值,需要提交的事务,建议新增、删除以及修改等使用
3. propagation=“”:控制事务传播行为
	3.1 当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务?(新建事务?在事务中执行?把事务挂起?报异常?)
	3.2 REQUIRED:默认值,如果当前有事务,就在事务中执行(不新建事务了);如果当前没事务,则新建一个事务。
	3.3 SUPPORTS:如果当前有事务,就在事务中执行;如果当前没事务,就在非事务状态下执行。
	3.4 MANDATORY:必须在事务内部执行。如果当前有事务,就在事务中执行;如果当前没有事务,则报错。
	3.5 REQUIRES_NEW:必须在事务中执行。如果当前有事务,则挂起当前事务(新建一个事务,独自在各自事务中执行);如果当前没有事务,则新建一个事务
	3.6 NOT_SUPPORTED:必须在非事务下执行。如果当前有事务,则挂起当前事务;如果当前没有事务,正常执行。
	3.7 NEVER:必须在非事务下执行。如果当前有事务,则报异常;如果当前没有事务,正常执行。
	3.8 NESTED:必须在事务中执行。如果当前有事务,则创建一个嵌套事务(与当前事务有关联-子事务);如果当前没有事务,则新建事务。
4. isolation=“”:事务隔离级别
	4.1 在多线程或并发访问下,如何保证访问到的数据的完整性。
	4.2 脏读:
		4.2.1 一个事务(A)读取到另一个事务中(B)未提交的数据;另一个事务(B)可能进行数据的改变,此时A事务读取到的数据可能和数据库中的数据不一致,此时认为数据是脏数据,读取脏数据的过程叫做脏读。
	4.3 不可重复读:
		4.3.1 主要针对的是某行数据(或行中某列)。
		4.3.2 主要针对的操所是修改操作。
		4.3.3 两次读取在同一个事务内
		4.3.4 当事务A在第一次读取数据后,事务B对事务A读取的数据进行修改,事务A中第二次读取的数据和之前的读取的数据就不一致,该过程叫做不可重复度。
	4.4 幻读:
		4.4.1 主要针对的操作是新增或删除。
		4.4.2 两次事务的结果
		4.4.3 事务A按照特定条件查询出结果后,事务B新增了一条符合这个条件的数据。事务A中再次查出的数据和数据库中的数据不一致,事务A好像出现了幻觉,该中情况叫做幻读。
	4.5 DEFAULT:默认值,由数据库自动判断应该使用什么隔离级别。
	4.6 READ_UNCOMMITTED:可以读取未提交数据,可能出现脏读、不可重复读以及幻读。效率最高。
	4.7 READ_COMMITTED:只能读取其他事务已提交数据,可以防止脏读,可能出现不可重复读以及幻读。效率最高。
	4.8 REPEATABLE_READ:读取的数据会被添加锁,防止其他事务修改此数据,可以防止脏读以及不可重复读,可能出现幻读。
	4.9 SERIALIZABLE:排队操作,对整个表添加锁。一个事务在操作数据库表时,另一个事务等待其事务完成后,才能操作相关表。最安全,效率最低。
5. rollback-for=“异常类型的全限定路径”
	5.1 当出现什么异常时,需要进行回滚。
	5.2 建议:给定该属性值。
		5.2.1 手动抛异常时,一定给该属性值。
6. no-rollback-for=“”
	6.1 当出现什么异常时不回滚事务。

常用注解

1. @Component:创建类对象,相当于配置<bean>
2. @Service与@Component功能相同
	2.1 写在ServiceImpl类上的
3. @Repository与@Component功能相同
	3.1 写在数据访问层类上
4. @Controller与@Component功能相同
	4.1 写在控制器类上
5. @Resource(不需要写对象的get/set方法)
	5.1 jdk中的注解
	5.2 默认按照byName注入,如果没有名称对象,按照byType注入。
		5.2.1 建议把对象名称和spring容器中对象名相同
6. @Autowired(不需要写对象的get/set方法)
	6.1 spring的注解
	6.2 默认按照byType注入。
7. @Value() 获取属性文件properties中的内容
8. @Pointcut() 定义切点
9. @Aspect() 定义切面类
10. @Before() 前置通知
11. @After() 后置通知
12. @AfterReturning() 后置通知,必须切点正确执行
13. @AfterThrowing() 异常通知
14. @Around() 环绕通知

附加-Ajax复习

1. 标准请求响应时,浏览器的动作(同步操作)
	1.1 浏览器请求什么资源就会跟随显示什么资源
2. Ajax:异步请求
	2.1 局部刷新:通过异步请求,请求到服务器资源数据后,通过脚本修改页面中部分内容。
3. Ajax由JavaScript推出
	3.1 后来由jQuery对js中Ajax代码进行的封装,达到使用方便的结果。
4. jQuery中Ajax的分类:
	4.1 第一层:$.ajax({属性名:值,属性名:值})
		4.1.1 jQuery中功能最全的,代码写起来相对最麻烦的。
		4.1.2 示例代码
<script type="text/javascript">
$(function(){
   /**
	url:请求服务器地址
	data:请求参数,json格式
	dataType:服务器返回数据类型
	error:请求出错执行功能
	success:请求成功执行功能,function(data):data服务器返回的数据.
	type:请求方式
   */
	$("a").click(function(){
		$.ajax({
			url:'demo',
			data:{"name":"张三"},
			dataType:'html',
			error:function(){
				alert("请求出错.")
			},
			success:function(data){
				alert("请求成功."+data)
			},
			type:'POST'
		});
		return false;
	});
});
</script>
	4.2 第二层(简化$.ajax)
		4.2.1 $.get(url,[data],[callback],[type])
		4.2.1 $.post(url,[data],[callback],[type])
			4.2.1.1 示例代码
$.post("demo",{"name":"张三"},function(data){
			alert(data);
      });
	4.3 第三层(简化$.get)
		4.3.1 $.getJSON(url,[data],[callback]) 相当于设置了$.get中:dataType="json"
		4.3.2 $.getScript(url,[callback]) 相当于设置了$.get中:dataType="script"
5.  如果服务器返回的数据是从表中取出,为了方便客户端操作返回的数据,一般服务器端返回的数据设置成json格式
	5.1 客户端把json当成对象或数组操作
6. json:数据格式。
	6.1 JsonObject:json对象,理解成java中的对象
		6.1.1 {"key":value,"key":value}
	6.2 JsonArray
		6.2.1 [{"key":value,"key":value},{"key":value,"key":value}]
	6.3 举例使用:jackson
List<Users> list=new ArrayList<>();
list.add(users);
list.add(users1);
ObjectMapper mapper = new ObjectMapper();
//JsonArray
String result = mapper.writeValueAsString(list);
7. <tbody>的使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function(){
   /**
	url:请求服务器地址
	data:请求参数,json格式
	dataType:服务器返回数据类型
	error:请求出错执行功能
	success:请求成功执行功能,function(data):data服务器返回的数据.
	type:请求方式
   */
	$("a").click(function(){
	/* 	$.ajax({
			url:'demo',
			data:{"name":"张三"},
			dataType:'html',
			error:function(){
				alert("请求出错.")
			},
			success:function(data){
				alert("请求成功."+data)
			},
			type:'POST'
		}); */
		$.post("demo",{"name":"张三"},function(data){
			var result="";
			for(var i=0;i<data.length;i++){
				result+="<tr>";
				result+="<td>"+data[i].id+"</td>"
				result+="<td>"+data[i].username+"</td>"
				result+="<td>"+data[i].password+"</td>"
				result+="</tr>";
			}
			//html相当于innerHtml 先清空后添加
			//使用append会追加不会先清空
			$("#mytbody").html(result);
		});
		return false;
	});
});
</script>
</head>
<body>
<a href="demo">跳转</a>
<table border="1">
	<tr>
		<th>编号</th>
		<th>姓名</th>
		<th>密码</th>
	</tr>
	<tbody id="mytbody"></tbody>
</table>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值