框架系列——Spring

Spring 框架

1.核心概念

1.1 AOP 面向切面编程(Aspect Oriented Programming)

将一些通用的逻辑集中实现,然后通过 AOP 进行逻辑的切入,减少了零散的碎片化代码,提高了系统的可维护性。

具体的含义可以理解为:通过代理的方式,在调用想要的对象方法时候,进行拦截处理,执行切入的逻辑,然后再调用真正的方法实现。

1)代理模式

静态代理

在编译时或者类加载时进行切面的织入,典型的 Aspect就是静态代理。

 package com.dao;
			public interface UserDao {
				 void login();
				 void add();
				 void update();
				 void search();
			}


package com.dao.impl;
			import com.dao.UserDao;
			
			public class UserDaoImpl implements UserDao {
			
				public void login() {
					System.out.println("login 执行了");
				}
			
				public void add() {
					System.out.println("add 执行了");
				}
			
				public void update() {
					System.out.println("update 执行了");
				}
			
				public void search() {
					System.out.println("search 执行了");
				}		
			}


package com.aop;
			import java.io.BufferedWriter;
			import java.io.FileWriter;
			import java.time.LocalDateTime;
			import com.dao.UserDao;
			import com.dao.impl.UserDaoImpl;
			
			public class UserDaoProxy  implements UserDao {
				//被代理的地象(委托对象)
				private UserDaoImpl impl=new UserDaoImpl();
				
				private String logPath="log.txt";
				
				public void add() {
					impl.add();
					try {
						BufferedWriter bw=new BufferedWriter(new FileWriter(logPath,true));
						bw.write(LocalDateTime.now()+"add 方法调用了  ");
						bw.newLine();
						bw.close();
					}
					catch(Exception ex) {
						ex.printStackTrace();
					}
				}
			
				public void update() {
					impl.update();
					try {
						BufferedWriter bw=new BufferedWriter(new FileWriter(logPath,true));
						bw.write(LocalDateTime.now()+"update 方法调用了  ");
						bw.newLine();
						bw.close();
					}
					catch(Exception ex) {
						ex.printStackTrace();
					}
				}
			
				public void search() {
					long begin=System.currentTimeMillis();
					impl.search();
					long end=System.currentTimeMillis();
					
					System.out.println("search 这个查询执行了"+(end-begin) +" ms ");
				}
				
				public void login() {
					long begin=System.currentTimeMillis();
					impl.login();
					long end=System.currentTimeMillis();
					System.out.println("login 执行了"+(end-begin) +" ms ");
				}
			}


package com.aop;
			import com.dao.UserDao;
			
			public class UserDaoProxyFactory {
				public static UserDao getUserDaoProxy() {
					return new UserDaoProxy();
				}
			
			}


package com.test;
		import com.aop.UserDaoProxyFactory;
		import com.dao.UserDao;
		import com.dao.impl.UserDaoImpl;
		public class Test1 {
		
			public static void main(String[] args) {
			//UserDao dao=new UserDaoImpl();	
				UserDao dao=UserDaoProxyFactory.getUserDaoProxy();
			
				dao.add();
				dao.update();
				dao.login();
				dao.search();
			}
		}


上面的程序,最关键的:
		1) 代理类和委托类实现的是同一个接口
		2) 代理类中,要有一个委托类的对象
		

静态代理的缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

动态代理

需要手写代码,JDK动态代理和CGLIB,区别等

1.2 IOC 控制反转 (Inversion of Control)

应用不负责依赖对象的创建,而是把它们的创建的控制权,交给外部容器,控制权的转移就是控制反转

class UserServlet{
    @Resource/@Autowired
	private UserDao dao;
}

1)Bean 的注入方式

setter方式
package com.dao;	
			public interface UserDao {
				 void login();
				 void add();
				 void update();
				 void search();
			}

package com.dao.impl;
			import com.dao.UserDao;
			
			public class UserDaoImpl implements UserDao{
			
				public void login() {
					System.out.println("UserDao login方法普通实现");
				}
			
				public void add() {
					System.out.println("UserDao  add方法普通实现");
				}
			
				public void update() {
					System.out.println("UserDao update方法普通实现");
				}
			
				public void search() {
					System.out.println("UserDao search方法普通实现");
				}
			
			}

package com.servlet;
			import com.dao.UserDao;
			
			public class UserServlet {
				private UserDao dao;
				
				//这个就是setter方法,由spring容器调用,将依赖对象注入进来
				public void setDao(UserDao dao) {
					System.out.println("setDao方法被容器调用了");
					this.dao = dao;
				}
			
				public void service() {
					dao.add();
					dao.login();
					dao.update();
					dao.search();
				}
			}

配置文件
			<bean name="userServlet" class="com.servlet.UserServlet">
				<property name="dao" ref="userDao" />
			</bean>
			
			<bean name="userDao" class="com.dao.impl.UserDaoImpl" />
构造器方式

Spring 倡导构造函数注入,因为构造器注入返回给客户端使用的时候一定是完整的。

2)Bean 的作用域

  • singleton:默认是单例,含义不用解释了吧,IOC 容器内部仅此
  • prototype:原型,多实例
  • request:每个请求都会新建一个属于自己的 Bean 实例,这种作用域仅存在 Spring Web 应用中
  • session:一个 http session 中有一个 bean 的实例,这种作用域仅存在 Spring Web 应用中-
  • application:整个 ServetContext 生命周期里,只有一个 bean,这种作用域仅存在 Spring Web 应用中
  • websocket:一个 WebSocket 生命周期内一个 bean 实例,这种作用域仅存在 Spring Web 应用中

2. 使用方式

2.1 名称空间

<?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:context="http://www.springframework.org/schema/context"
			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.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
		
		</beans>
		
            
            第一行 <?xml version="1.0" encoding="UTF-8"?> 这叫xml文档声明
		要注意,它的格式非常固定,而且它必须位于第一行,前面不能任何内容 (包扩空格和注释)
            
            第二行 xmlns="http://www.springframework.org/schema/beans"    
	  			xmlns 是 xml namespace 的简写,称为名称空间,后面跟的"http://www.springframework.org/schema/beans" 是名称空间的名称,每个名称空间名称,都对应着一个约束文件(Schema 语法) , 可以在后面找到:
	   			 "http://www.springframework.org/schema/beans 					http://www.springframework.org/schema/beans/spring-beans.xsd  ... "
	    
	第四行 xmlns:aop="http://www.springframework.org/schema/aop"  后面的:aop 是指明名称空间前缀,如果有前缀,则引用
     该名称空间中的内容的时候,要加上前缀,比如 <aop:config></aop:config>
     如果没有前缀的,称为默认名称空间

2.2 注解装配

  1. 引入context名称空间
  2. 开启<context:annotation-config />
  3. 注解声明依赖关系 例如:
		@Resource(name = "userSuperDao")  												//如果 UserDao  接口的实现类只有一个,则 name 属性可以省去
		private UserDao dao;

补充说明:
@Resource 注解:
① 它是来源于 import javax.annotation.Resource; 它不属于spring ,它是jdk中的
② 默认它是按名称装配,然后再按类型装配置,如果指明了名称,则严格按名称进行装配置
③ 它也可以写在 set方法上
④ 从jdk8以后,使用 @Resource 注解要额外导包

​ @Autowired 注解
​ ① 它是 import org.springframework.beans.factory.annotation.Autowired; 它属于spring
​ ② 默认它是按类型进行装配置
​ ③ 如果想按名称进行装配,则要和@Qualifier注解配合使用 @Autowired @Qualifier("userSuperDao")
​ ④ 默认情况下,它不注入null值 如果允许,可以 @Autowired(required = false)

2.3 自动扫描

  1. 引入 context 名称空间
  2. 开启自动扫描

<context:component-scan base-package="com.servlet" />
<context:component-scan base-package="com.dao" />

<context:annotation-config /> //这个可以去掉了,因为开启自动扫描以后,相当于自动加入了这个配置

它会自动扫描指定的包和子包下的带有以下注解的类:
@Controller //控制层
@Service //用于业务层
@Repository //持久层
@Component //其他

3.事务管理

3.1 注解方式

①引入名称tx空间
		  <?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:context="http://www.springframework.org/schema/context"
				xmlns:tx="http://www.springframework.org/schema/tx"
				xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
					http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
					http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
					   ....
					  
		  ②配置一个事务管理器
		      <context:component-scan base-package="com" />
		      
		  	  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
					   <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
					   <property name="url" value="jdbc:mysql://localhost:3306/cms?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC&amp;useSSL=false"/>
					   <property name="username" value="root"/>
					   <property name="password" value="root"/>	    
				  </bean>
	  
		  	  <bean  name="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
					    <property name="dataSource" ref="dataSource" />
				  </bean>
					
		  ③开启注解管理事务
		     <tx:annotation-driven transaction-manager="txManager"/>
		
		
		  ④在方法上加相关的注解 
					@Transactional
					public int addUser(UserInfo user) {
						  String sql="insert into  userInfo (userName,password,note) values (?,?,?)";
						
					    int r= t.update(sql,user.getUserName(),user.getPassword(),user.getNote());	
					    
					    int a=9/0;
				
					    return r;
					}

然后再运行程序,发现在程序出错的情况下,数据库中是不会添加数据的

​ @Transactional 注解可以写在方法上,也可以写在类体上

事务的传播行为: (其实讨论的就是 propagation 的取值情况)

  1. ----REQUIRED:业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务。

  2. ----NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。
    如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。

  3. ----REQUIRESNEW:(requiresnew) 属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。
    如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行

  4. ----MANDATORY (mandatory,强制的,命令的,受委托的):该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。

  5. ----SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。

  6. ----Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。

  7. ----NESTED:nested (窝,嵌套)如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效

3.2 xml方式

<bean  name="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		  	  <property name="dataSource" ref="dataSource" />
			</bean>
			
			<aop:config>
				<aop:pointcut expression="execution(* com.dao.UserDaoImpl.*(..))" id="txPointCut"/>
				<aop:advisor advice-ref="txAdvice"  pointcut-ref="txPointCut" />	
			</aop:config>
			
			<tx:advice id="txAdvice" transaction-manager="txManager">
				<tx:attributes>
					<tx:method name="get*"  propagation="NOT_SUPPORTED"  />
					<tx:method name="*"   />
				</tx:attributes>
			</tx:advice>
posted @ 2024-07-30 00:32  AbjLink  阅读(2)  评论(0编辑  收藏  举报