Spring快速笔记2

10 篇文章 0 订阅
概述:Spring的概述、SpringIOC入门(XML)、Spring的Bean管理、Spring属性注入Spring的IOC的注解方式、Spring的AOP开发(XML)Spring的AOP的注解开发、Spring的声明式事务、JdbcTemplate。SSH的整合、HibernateTemplate的使用、OpenSessionInViewFilter的使用。 ...
摘要由CSDN通过智能技术生成

概述:

  • Spring的概述、SpringIOC入门(XML)、Spring的Bean管理、Spring属性注入
  • Spring的IOC的注解方式、Spring的AOP开发(XML)
  • Spring的AOP的注解开发、Spring的声明式事务、JdbcTemplate。
  • SSH的整合、HibernateTemplate的使用、OpenSessionInViewFilter的使用。

 

1. 快速引入遗留问题

在案例中,遗留的一个程序问题是:每次请求都会创建一个Spring的工厂,这样浪费服务器资源,应该一个项目只有一个Spring的工厂。在实际开发中,应该遵循:

  • 在服务器启动的时候,创建一个Spring的工厂。

  • 创建完工厂,将这个工厂类保存到ServletContext中。

  • 每次使用的时候都从ServletContext中获取。

在整合Web项目时的解决方法:引入Spring_web.jar,使用ServletContextListener来监听ServletContext对象的创建和销毁,在使用时通过工具类加载工厂applicationContext。也就是通常说的“Spring核心监听器”。注意:Spring_wab.jar中默认使用的是/WEB-INF/applicationcontext.xml,要手动修改。

 

2. IOC的注解方式

2.1 使用案例
  • IOC注解方式的JAR包:4核心+2日志,Spring4.x后额外需要一个aop的依赖。

  • xml中引入Context的相关约束:解压目录下/docs/spring-framework-reference/html/xsd-configuration.html

  • 示例:

    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        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.xsd">	
    	<!-- 使用context来告知Spring的注解形式 -->
    	<context:component-scan base-package="com.leehao.springlearning.Anno1" />
    </beans>
    -------------------------------------Java---------------------------------------
    @Component(value="userDao")
    public class UserDaoImpl implements UserDao {
    	@Value("HHHH")
    	private String name;	
    //	public void setName(String name) {
    //		this.name = name;
    //	}	
    	@Override
    	public void save() {
    		System.out.println("Anno1....save:" + name);
    	}	
    }
    

 

2.2 Component类注解
  • 注解Bean时,使用时必须在xml中配置<context:component-scan>,按名称注入
    • @符号标识,是一个类;
    • 可以使用注解代替xml配置
    • @component 取代<bean calss=>
    • @component(value=“id”) 取代<bean id=,calss=>,value可以省略
  • Component注解的三个衍生注解,便于开发,后续Spring将逐渐分开支持
    • controller:Web层
    • service:Service层
    • Repository:Dao层
    • 使用与直接使用Component等效

 

2.3 注入属性的注解

属性的注入可以直接在属性的上方,也可以另外生产set方法,对方法进行修饰。

  • 普通值:@Value

  • 对象引用:@Autowired,按属性类型自动注入,单独可以使用。一般地,和@Qualifier(value=“”)一同使用

    • 对象引用2:@Resource(name=“”),按照名称进行注入(Spring引用的其他接口规范的注解),name不可省略。
    @Service("userService")
    public class UserServiceImpl implements UserService {
    //	@Autowired
    //	@Qualifier(value="userDao")  //两个注解同时使用,按名称注入,value可以省略
    	@Resource(name="userdao")
    	private UserDao userDao;	
    	@Override
    	public void save() {
    		userDao.save();
    		System.out.println("UserService save...");
    	}
    }
    

 

2.4 Bean的其他注解
  • 生命周期的注解

    • @PostConstruct:初始化注解,相当于<bean>标签中的init-method
    • @PreDestroy:销毁注解,相当于<bean>标签中的destroy-method
  • 类/bean作用范围注解,后三种不常用

    • @Scope(“prototype”):默认为singleton,单例;

    • 同样,在多例中Spring无法进行销毁

    • request

    • session

    • globalsession

 

2.5 XML和注解方式比较
  • 比较

    • XML结构清晰,任何情况下都适用
    • 注解方便,但是只能对自定义的类进行注解,如一些默认的源码或工具类无法配置
  • 混合开发的方式

    • 如XML管理Bean,属性注入使用注解
    • 注意:使用<context:component-scan>开启Bean的注解,而若只用属性注入等注解时,只开启<context:annotation-config /> 也可。
    <!-- 使用context来告知Spring的注解形式 -->
    <!-- 	<context:component-scan base-package="com.leehao.springlearning" /> -->
    <!-- 可以不开启扫描,只开启注释配置 -->
    <context:annotation-config />
    <bean id="productDao" class="com.leehao.springlearning.Anno2.ProductDao" />
    <bean id="userService" class="com.leehao.springlearning.Anno2.UserServiceImpl"/>
    
  • 1547185993541


3 AOP

面向切面编程,底层以代理方式实现;用于事务管理、性能监控、缓存、日志等。

3.1 概念

AOP是OOP的一种延伸,一种新的设计理念。是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
  • 经典应用:事务管理、性能监视、安全检查、缓存、日志等
  • Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,运行期通过代理方式向目标类织入增强代码
  • AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入

 

3.2 Spring的代理机制

Spring底层使用动态代理的机制,来完成功能的增强;在不改变源代码基础上进行拓展增强。

  • JDK 的动态代理:针对实现了接口的类(接口+实现类)产生代理,Spring默认使用的代理机制

  • Cglib 的动态代理 :针对没有实现接口的类产生代理。应用底层的字节码增强的技术,生成当前类的子类对象。类似于Javassist,Hibernate里使用的——早期版本用的也是cglib。

  • JDK的底层实现——手动示例:

     * 实现InvocationHandler完成自身的代理执行,使用匿名内部类或其他类亦可
    public class JDKProxy implements InvocationHandler {
    	private UserDao userDao;   //通过目标对象的引用,对其进行功能的增强
    	public JDKProxy(UserDao userDao) {
    		this.userDao = userDao;
    	}
    	//生成代理对象
    	public UserDao createProxy() {
    		UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
    				userDao.getClass().getClassLoader(), 
    				userDao.getClass().getInterfaces(), 
    				this);
    		return userDaoProxy;
    	}
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		//实现增强,proxy创建实例后的执行方法
    		System.out.println("增强之前....");
    		return method.invoke(userDao, args);   //执行原来的方法
    	}	
    }
    
  • Cglib的底层实现——手动示例:

    spring和核心包已经包含了cglib的包库。Cglib使用一个Enhancer的核心对象来创建代理对象,但需要说明的是,它采用的是继承目标对象的方式,一旦目标对象是Final时则无法实现。

    public class CglibPorxy implements MethodInterceptor{
    	private CustomerDao customerDao;
    	public CglibPorxy(CustomerDao customerDao) {
    		this.customerDao = customerDao;
    	}
    	//创建代理
    	public CustomerDao createCustomer() {
    		//1.enhancer核心
    		Enhancer enhancer = new Enhancer();
    		//2.继承目标类
    		enhancer.setSuperclass(CustomerDao.class);
    		//3.通过回调生成代理
    		enhancer.setCallback(this);		
    		return (CustomerDao) enhancer.create();
    	}
    	@Override
    	public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    		//执行增强
    		System.out.println("增强...");		
    		return method.invoke(customerDao, args); //methoProxy.invokeSuper(customerDao, args);
    	}	
    }
    

 

3.3 Spring的AOP——基于AspectJ的XML

AOP是一个概念,存在AOP联盟,而Spring只是较好地运用起来。Spring原始的AOP技术较为复杂,引入了一个AspectJ的框架,来支持Spring的AOP编程。

  • AOP相关术语

    Joinpoint(连接点) :所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
    Pointcut(切入点) :所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
    Advice(通知/增强) :所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能)
    Introduction(引介) :引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或 Field
    Target(目标对象) :代理的目标对象
    Weaving(织入) :是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而AspectJ 采用编译期织入和类装载期织入
    Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类
    Aspect(切面): 是切入点和通知(引介)的结合
    
  • 1547191530771

  • JAR包:

    • 基础Spring的4+2
    • AOP:spring-aop、aspectj、aop联盟、spring-aspects整合包
  • spring的aop的XML约束:xmlns命名空间

 

3.4 案例Demo
  • 整合Spring的Junit,使用注解的方式完成工厂的加载,对applicationConetext.xml文件进行解析,在使用时直接注入需要获取的bean,方便测试。

    • Jar包:spring-test.xxx.jar

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:applicationContext.xml")
      public class AspectJDemo1 {
      	@Resource(name="productDao")
      	private ProductDao productDao;	
      	@Test
      	public void demo1(){
      		productDao.save();
      		productDao.delete();
      		productDao.update();
      	}
      }
      
  • 将需要增强的功能通过切面类来组织,并使用Spring中的xml进行配置。

    <!-- aspectj -->
    <bean id="productDao" class="com.leehao.springlearning.aspectj1.ProductDaoImpl"/>
    <!-- aop的配置 
        1.切面类(增强的封装):执行的什么增强
        2.切面:将哪个对象用到了什么增强,联系在一起;执行什么样的增强(前,后,异常等)
        3.切入点表达式:在对象的什么位置执行
    -->
    <bean id="myAspect" class="com.leehao.springlearning.aspectj1.MyAspect"/>
    <aop:config >
        <!-- 切入点表达式 -->
        <aop:pointcut expression="execution(* com.leehao.springlearning.aspectj1.ProductDaoImpl.save(..))" id="pointcut1"/>
        <!-- 切面 -->
        <aop:aspect ref="myAspect">
            <aop:before method="checkPri" pointcut-ref="pointcut1"/>
        </aop:aspect>
    </aop:config>
    
  • Apsect的通知类型:

    • 前置通知:可以使用Jointpoint获得切入点的相关属性

      public void checkPri(JoinPoint joinPoint){
          System.out.println("增强..." + joinPoint);
      }
      -------------------------------------------------------------------
      <aop:aspect ref="myAspect">
      	<aop:before method="checkPri" pointcut-ref="pointcut1"/>
      </aop:aspect>
      
    • 后置通知:可以获得方法的返回值,但xml的配置和方法的通知方法的形参名必须一致

      public void writeLog(Object res) {
      		System.out.println("后置....日志:" + res);
      	}
      -------------------------------------------------------------------
      <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="res"/>
      
    • 环绕通知:前后执行信息,使用ProceedingJoinPoint类型参数控制切入点的执行(可以阻止)。

      public Object around(ProceedingJoinPoint point) throws Throwable {
      		System.out.println("环绕前..");
      		Object object = point.proceed();
      		System.out.println("环绕后..");
      		return object;		
      	}
      -------------------------------------------------------------------
      <aop:around method="around" pointcut-ref="pointcut3"/>
      
    • 异常抛出

      public void afterThrow(Throwable tw) {
      		System.out.println(tw.getMessage());
      	}
      -------------------------------------------------------------------
      <aop:after-throwing method="afterThrow" pointcut-ref="pointcut1" throwing="tw"/>
      
    • 最终通知:相当于finally块

      public void finalReturn() {
      		System.out.println("finallyReturn..");
      	}
      -------------------------------------------------------------------
      <aop:after method="finalReturn" pointcut-ref="pointcut1"/>
      

 

3.5 Aop 的切入点表达式

切入点表达式基于execution函数完成。

表达式:[方法访问修饰符] 方法返回值 包名.类名.方法名(方法的参数)

  • public * cn.itcast.spring.dao.*.*(…)
  • * cn.itcast.spring.dao.*.*(…) dao下的所有类的所有方法
  • * cn.itcast.spring.dao.UserDao+.*(…)* ——+号表示含其子类
  • * cn.itcast.spring.dao…*.*(…) dao下所有子包的所有类的所有方法

 

 

4 AOP的注解方式

基于AspectJ的注解方式。除了Bean之外的文件需要在xml文件中配置外,其他如切面类、切入点(含表达式)、通知类型等都直接在需要增强的地方使用注解来完成。

  • 切面类:@Aspect

  • 通知类型:@Before,@After,@AfterReturning,@Around,@AfterThrowing

  • @Aspect
    public class MyAspectAnno {
    	@Before(value="execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.save(..))")
    	public void before(JoinPoint joinPoint) {
    		System.out.println("before..." + joinPoint);
    	}	
    	@AfterReturning(value="execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.delete(..))",returning="res")
    	public void afterReturn(Object res) {
    		System.out.println("afterReturn..." + res);
    	}	
    	@Around("execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.update(..))")
    	public Object around(ProceedingJoinPoint point) throws Throwable {
    		System.out.println("环绕前..");
    		Object object = point.proceed();
    		System.out.println("around...后");
    		return object;
    	}  
    	@AfterThrowing(value="execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.query(..))",throwing="e")
    	public void afterThrow(Throwable e) {
    		System.out.println("afterThrow..."+e.getMessage());
    	}	
    	@After("execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.query(..))")
    	public void finalThrow() {
    		System.out.println("finalThrow....");
    	}
    }
    
  • 注解切入点:可以在使用注解时,单独定义切入点,在需要使用时进行引用即可。可以是作为将执行的切入点表达式抽离出来了。

    //声明切入点注解
    @Pointcut(value="execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.save(..))")
    public void pointCut1(){}
    @Pointcut(value="execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.delete(..))")
    public void pointCut2(){}	
    @Pointcut(value="execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.update(..))")
    public void pointCut3(){}  //value可省略
    @Pointcut("execution(* com.leehao.springlearning.aop_anno.CustomerDaoImpl.query(..))")
    public void pointCut4(){}
    ----------------------------使用---------------------
    @Before(value="MyAspectAnno.pointCut1()")   //value可省略
    public void before(JoinPoint joinPoint) {
        System.out.println("before..." + joinPoint);
    }
    

 

5 Spring的JDBC

Spring为一站式开发框架,其持久层的支持则是ORM框架,另外一种重要的就是JDBC。Spring提供了许多的模板,简化了对各个持久层框架的支持,JDBC模板就是其中一种,另外还有如支持Hibernate的、Mybatis的模板。

  • 一个示例:

     * 使用JDBC模板进行创建连接,对数据库进行操作
     * JDBC模板的使用类似于JDBCUtils
    public void demo1(){
        //1.创建连接池
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/springlearning");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        //2.创建JDBC模板,需要连接池
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.update("insert into user values(null, ?, ?)", "王五", 2000d);
    }
    

 

5.1 JDBC的模板使用

使用Spring的注解方式,将JDBC模板及其依赖的数据源,都交给Spring去完成,在配置文件中配置相应的Bean。注意:Spring4之后,使用时需要引入AOP的jar包。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcDemo2 {
	@Resource(name="jdbcTemplate")
	private JdbcTemplate jdbcTemplate;
	@Test
	public void demo1() {
		jdbcTemplate.update("insert into user values(null, ?, ?)", "zhaoliu", 2000d);
	}
}
-----------------------------------------------------------
<!-- 配置数据驱动源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!-- 设置属性 -->
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/springlearning"/>
    <property name="username" value="root" />
    <property name="password" value="123456"/>
</bean>	
<!-- JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

 

5.2 其他的开源数据库连接池
  • DBCP:DataBase Connection Pool。使用第三方的开源数据库连接池,性能更加稳定,适用于生成环境。需要引入commons的两个包:

    • com.springsource.org.apache.commons.pool-1.5.3.jar
    • com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
    <!-- DBCP数据源 -->
    <bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/springlearning"/>
        <property name="username" value="root" />
        <property name="password" value="123456"/>
    </bean>
    
  • C3P0:com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar

    <!-- C3P0 -->
    <bean id="dataSource3" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springlearning"/>
        <property name="user" value="root" />
        <property name="password" value="123456"/>
    </bean>
    

 

5.3 使用properties配置数据源

将数据源设置的相应的值,以properties的格式保存到属性文件中;在XML中配置对properties文件的引用,然后使用${key}的形式进行引用。

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springlearning
jdbc.username=root
jdbc.password=123456
--------------------------------------------------------------
<!-- 引入properties -->
<!-- 方式1 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:jdbc.properties" />
</bean>
<!-- 方式二 更常用-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource4" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}" />
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}"/>
</bean>

 

5.4 JDBC的CRUD操作
//JDBC的CRUD操作
@Test
public void demo2(){
    //修改
    jdbcTemplate.update("update user set name=? where id=?", "666", 4);
    //删除
    jdbcTemplate.update("delete from user where id=?", 4);
}
@Test
public void demo3(){
    Integer integer = jdbcTemplate.queryForObject("select count(*) from user", Integer.class);
    System.out.println(integer);
}
.....其他的query/queryForObject/update等操作方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值