培训第2个月的第5天----用xml的方式配置切面

               昨天其实遇到一个非常有意思的问题,但是昨天学的没有总结成博客(笔记),所以今天就直接总结一下今天学的。其实我觉得如果一个知识点现在明白了,但是往后学的某一个瞬间你一定会疑惑当初的这个知识点那么理解到底对不对。

                好,我们现在学习一下用xml配置文件的方式来增强目标方法。也就是实现aop。

一.什么是aop

               这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。AOP是Spring提供的关键特性之一。AOP即面向切面编程,是OOP编程的有效补充。使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统(也就是将代码独立编写,然后插入到指定的地方实现功能)。从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑——比如权限管理,事物管理,日志记录,或者使原来的代码变得复杂不好维护(如果在原来的代码中继续编写)。如果在java代码中进行事务管理是非常麻烦的,但是如果交给配置文件,就可以通过xml的方式来使需要事务的方法实现事务管理。这些系统性的编程工作都可以独立编码实现,然后通过AOP技术切入进系统即可。从而达到了 将不同的关注点分离出来的效果。

二.aop的相关概念

               1) Pointcut :切点,符合切点表达式的连接点,也就是真正被切入的地方;我们可以将切点简单的想象成要扩充功能的方法。

               2) Aspect :切面,切入系统的一个切面。比如事务管理是一个切面,权限管理也是一个切面;我们可以将切面简单的理解为要为系统扩充的功能。

               3) Join point :连接点,也就是可以进行横向切入的位置;是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个join point,因为在切面切入系统的时候,是在切点切入的,而不是在连接点。

             4)advice:通知,切面在某个连接点执行的操作(具体分为几种: Before advice , After returning advice , After throwing advice , Aer (finally) advice , Around advice );是point cut 的执行代码,是执行“方面”的具体逻辑。通知和切点就组成了切面。

三.代码演示---切点和切面

                下面的spring核心配置文件配置了方法的前置增强和事务管理 。下面让我们来理解一下这个代码。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 将hibernate整合到spring中 -->
<beans	xmlns = "http://www.springframework.org/schema/beans"
		xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"		
		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-3.2.xsd
			   http://www.springframework.org/schema/aop
			        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
			        	http://www.springframework.org/schema/tx
			        		http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

<!-- 使用没有实现接口的增强类 -->
<!-- 使用实现确定接口的增强类 -->   
            <!-- 创建目标类 -->
            <bean id="userDaoImpl1" class="com.java.DaoImpl.UserDaoImpl1"></bean>
        
            <!-- 创建增强类-->
            <bean id="myAdvice" class="com.java.Advice.MyAdvice"></bean>
            <bean id="myAdvice2" class="com.java.Advice.MyAdvice2"></bean>
            
            
        <aop:config proxy-target-class="true">
            <!-- 创建切点(所有被增强的方法) -->
            <aop:pointcut id="pointcut1" expression="execution(* com.java.DaoImpl.UserDaoImpl1.*(..) )"></aop:pointcut>
            <aop:pointcut id="pointcut2" expression="execution(* com.java.DaoImpl.UserDaoImpl1.delete_user(..) )"></aop:pointcut>
              
            <!-- 配置增强 (默认的增强方法) -->
            <aop:advisor advice-ref="myAdvice2" pointcut-ref="pointcut1"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
            
            <!-- 创建切面(指明增强类中的确切增强方法) --> 
            <aop:aspect id="aspect" ref="myAdvice">
                  <aop:before method="adviceMethod2" pointcut-ref="pointcut2"/>
                  <aop:after method="adviceMethod1" pointcut-ref="pointcut1" />
            </aop:aspect>
           
        </aop:config>
       
<!-- 配置事务所需配置 -->

           <!-- 配置数据源 -->
           <bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" scope="singleton">
			   <property name="url" value="jdbc:mysql://localhost:3306/ssgl"></property>
			   <property name="username" value="root"></property>
			   <property name="password" value="root"></property>
			   <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		   </bean>

           <!-- 配置事务管理器 -->
           <bean id="dataSourceTransactionManager" class=" org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="basicDataSource"></property>
           </bean>
           
           <!--配置事务增强  -->
           <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
                <tx:attributes>
                     <!-- 所有的方法都用事务来管理,精确到某一个方法,用确定的事务方式来管理 -->
                	<tx:method name="update_user" rollback-for="java.lang.Exception"></tx:method>
                </tx:attributes>
           </tx:advice>

        <!-- spring集成hibernate  获得LocalSessionFactoryBean-->
		<bean id = "localSessionFactoryBean" class = "org.springframework.orm.hibernate3.LocalSessionFactoryBean">
			<property name="dataSource" ref = "basicDataSource"></property>
			<!-- hibernate的hbm.xml的映射 -->
			<property name="mappingLocations">
				<!-- 避免hbm文件过多采用正则表达式配置风格 -->
					<value>classpath:com/java/Bean/*.hbm.xml</value>
			</property>
			<!-- 额外属性 -->
			<property name="hibernateProperties">
				<props>
					<!-- 指定HQL按照哪个数据库方言进行sql语句的翻译 -->
					<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
					<!-- 开启在控制台打印sql语句的能力 -->
					<prop key="hibernate.show_sql">true</prop>
					<!-- 开启了可以使用二级缓存的能力 -->
					<prop key="hibernate.cache.use_second_level_cache">true</prop>
					<!-- 指定缓存提供商 -->
					<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
					<!-- 开启查询缓存 -->
					<prop key="hibernate.cache.use_query_cache">true</prop>
				</props>
			</property>
	     </bean>
          
          <!-- 配置hibernate模板类 -->
		  <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
			   <property name="sessionFactory" ref = "localSessionFactoryBean"></property>
		  </bean> 
	
          <!-- 配置Dao层类 -->
          <bean id="userDao" class="com.java.DaoImpl.UserDaoImpl1">
               <property name="hibernateTemplate" ref="hibernateTemplate"></property>
          </bean>















        
        
        

</beans>

                  代码中写了两种方法增强的形式,一种是用没有实现接口的增强类给普通类增强,也就是没有实现像 MethodBeforeAdvice 这样的定义了固定增强方式接口的类。另一种则是用实现了固定增强方式接口的类来给目标类增强。

              我们先来看第一种:

package com.java.DaoImpl;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.java.Bean.User;
import com.java.Dao.UserDao;

public class UserDaoImpl1 implements UserDao {
	//获取模板类 
	HibernateTemplate hibernateTemplate;
			
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
			this.hibernateTemplate = hibernateTemplate;
	}

	@Override
	public void add_user(User user) {
		System.out.println("增加方法被执行");
	}

	@Override
	public void delete_user(User user) {
		System.out.println("删除方法被执行");
	}

	@Override
	public void update_user(User user) {
		System.out.println("更新方法被执行");
		//通过模板类来操作数据库
		hibernateTemplate.update(user);
	}

	@Override
	public void select_all_user() {
		System.out.println("查询方法被执行");
	}

}

                      我们创建了目标类,并在spring中配置,用spring框架来管理。有了目标类,我们还需要一个增强类,用来给目标类z增强。

package com.java.Advice;

//不实现任何接口的增强类(也就是没有指明确切增强形式的增强类)
public class MyAdvice {
      
	 //增强方法一
	 public void adviceMethod1() {
		 System.out.println("增强方法一被执行");
	 }
	 
	 //增强方法二
     public void adviceMethod2() {
		 System.out.println("增强方法二被执行");
	 }
}

                        好,下面我们来看配置文件中的配置。

 

 

 

                 具体的可以看上面的源代码。我们通过创建切点,来确定为哪一个或哪些个方法进行增强,但是知道了要被增强的方法,我们需要知道怎样给这些方法进行增强。而切面就表达了这一点,配置的切面描述了用增强类中的具体的某一个方法来给切点进行增强,也定义了增强的方式,并通过pointcut-ref 属性将切点和切面联系到一起,这样我们在只需要创建目标类的对象,并且调用相应的方法就可以。

                  接下里我们看第二种方式。这种方式和第一种方式比较起来就相对简单,因为它已经定义了要增强的方式,比如是前置增强还是后置增强,所以我们只需要定义切点,并将切面和切点联系起来即可。

package com.java.Advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

//实现固定接口的增强类(也就是确定了增强方式的增强类)
public class MyAdvice2 implements MethodBeforeAdvice{
   @Override
   public void before(Method method,Object[] objArr,Object obj) {
	   System.out.println("前置增强被调用");
	   
   }
}

 

 

                所以我们只需要用advisor标签将切点和切面联系起来,这样只需要创建mu'b目标类对象,调用方法就能看到,方法已经被增强。

四.代码演示----用xml来配置事务切面

               我们可以简单的将切面ka看作成一个功能,而事务就是一个功能,但是要怎样用xml来实现事务呢?我们现在就来看一下。

                我们想一想既然我们要进行事务管理,那肯定是对数据库的,是哪一个数据库呢?这就需要我们进行配置数据源,数据源就指定了对哪一个数据库进行事务管理。

                有了数据源,我们就需要事务管理器,把数据源交给事务管理器,之后就用事务管理器来管理这个数据库的事务。 

  

             有了事务管理器,就用事务管理器来给所需要事务的方法添加事务,  哪个方法需要进行事务操作呢?我们可以定义切点来表示切点中的方法都可以用事务功能,但是切点中的哪一个具体方法要用事务要配置一下。

                上述代码我们可以看到,事务管理器管理update_user()方法,只要这个方法抛出异常,那么就进行事务回滚。但是我们只知道方法名,并不知道这个update_user()具体在哪个包下,所以我们要用切点进行方位确定。

                这就表明给pointcut1这个切点中的update()方法进行事务管理了。

五.将hibernate整合到spring中

                通过把数据源给 LocalSessionFactoryBean 来过的操作这个数据库的sessionFactory实例。在sessionFactory里面设置属性。

                 其实在写配置文件的过程中,标签之间是怎样的依赖是根据代码决定的,我们只是把用java代码编写的部分挪到了xml文件中,所以我们根据java代码就能写出xml文件。根据这个,我们像上述代码一样配置了sessionFactory的属性。

                 之后通过获得 hibernate模板类来操作数据库。

                由于hibernateTemplate模板类中有一个sessionFactory属性,所以hibernateTemplate类中有sessionFactory对象,而sessionFactory对象可以获得操作数据库的session对象,所以hibernateTemplate也可以直接操作数据库(我是这么理解的,不知道对不对)。

                   为了编写代码简单,我们也可以对hibernateTemplate进行封装。

                   这样我们就可以创建Use人DaoImpl类的实例来操作数据库,简单有实用,嘻嘻嘻嘻嘻。

猜你喜欢

转载自blog.csdn.net/qq_41160264/article/details/81986328