Spring的入门学习(三)

Spring的AOP的基于AspectJ的XML的开发

  • 摘要:AOP的概述
    AOP:面向切面编程,是OOP(面向对象)的扩展和延伸,是用来解决OOP遇到问题。
  • SpringAOP底层实现技术:
  1. JDK的动态代理实现(接口)
    原理:利用反射的原理,给予真实业务对象生产代理对象,在真实业务执行的前后进行相关操作.
package javaApi.com;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
 * 实现一个动态的代理设计模式
 * 需要一个自定义proxy代理类来实现InvocationHandler
 * 而这个自定义的代理类是
 */
class ALproxy implements InvocationHandler{//实现接口InvocationHandler
	private Object target;//保留真实业务
	/**
	 * 进行真实业务对象与代理业务对象的绑定处理
	 * @param target 真实的业务处理
	 * @return	proxy代理业务生成的对象
	 */
	public Object bind(Object target) {
		this.target=target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
	}
	//切面通知
	public boolean connect() {
		System.out.println("开启消息通道");
		return true;
	}
	//切面通知
	public void close() {
		System.out.println("关闭消息通道");
	}
	/*重写InvocationHandler里面的方法 外面去调用send();方法的时候,这个时候其实
	代理对象进行调用invoke方法,需要经过InvocationHandler这个接口进行处理操作*/
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object returndata=null;
		if(this.connect()) {
			 returndata=method.invoke(this.target, args);
			this.close();
		}
		return returndata;
	}
	
}

//发送消息的接口
interface Iinformation{
	public abstract void send();
}
//实现消息接口
class information implements Iinformation {
	public void send() {
		System.out.println("information消息发送");
	}
}
//测试
public class ital04 {
	public static void main(String[] args) {
		Iinformation infor=(Iinformation)new ALproxy().bind(new information());
		infor.send();
	}
}

  1. Cglib的动态代理实现(无接口)
    原理:给予真实业务对象生产一个子类,继承真实业务,覆盖其中的方法实现增强,
/**
* 使用cglib动态代理
* 
* @author yanbin
* 
*/
class CglibProxy implements MethodInterceptor {
    private Object target; //保留真实业务对象
    /**
     * 创建代理对象
     * @param target 真实主体对象
     * @return
     */
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer(); //负责代理操作的程序类
        enhancer.setSuperclass(this.target.getClass()); //假定一个父类
        // 回调方法 设置代理类
        enhancer.setCallback(this);
        // 创建代理对象进行返回
        return enhancer.create();
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object returndata=null;
		if(this.connect()) {
			 returndata=methodProxy.invoke(this.target, args);
			this.close();
		}
		return returndata;
    } 
}
//主体类
class Message{
	public void send() {
		System.out.println("information消息发送");
	}
}
public class demo{
	public static void main(String[] args) throws Exception{
	Message message1=new Message();
	Message message2=(Iinformation)new CglibProxy().getInstance(message);
	//消息发送
	message2.send();
}
}
  • AOP的相关术语
    连接点:可以被拦截的点。
    切入点:真正被拦截的点。
    通知:增强方法
    引介:类的增强
    目标:被增强的对象
    织入:将增强应用到目标的过程。
    代理:织入增强后产生的对象
    切面:切入点和通知的组合
  • AOP的入门开发
  • 通知类型(名词解释百度)
    前置通知
    后置通知
    环绕通知
    异常抛出通知
    最终通知
  1. Spring提供织入接口实现 (aopxmll开发)
<!-- aop的xml的基本配置 -->
	<context:component-scan base-package="spring_aop_demo01.UserService"></context:component-scan>
	<bean id="log" class="spring_aop_demo01.UserService.proxy.log"></bean>
	<bean id="after" class="spring_aop_demo01.UserService.proxy.after"></bean>
	<aop:config>
	<!-- 切入点的配置 -->
	<aop:pointcut expression="execution(* spring_aop_demo01.UserService.UserServiceImp.add(..))" id="pointcut1"/>
	<aop:pointcut expression="execution(* spring_aop_demo01.UserService.UserServiceImp.seach(..))" id="pointcut2"/>
	
	<!--切面的配置  -->
	<aop:advisor advice-ref="log" pointcut-ref="pointcut1"/>
	<aop:advisor advice-ref="after" pointcut-ref="pointcut2"/>
	</aop:config>

log.java通知和after.java通知

//前置通知
public class log implements  MethodBeforeAdvice{
	/**
	 * 这个表示的就是前置通知
	 * method 表示的是被调用的方法的对象
	 * args 	表示被调用方法的参数
	 * target 表示的是被调用方法的目标对象
	 */
	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了");	
	}
}
//后置通知
public class after implements AfterReturningAdvice {
	/**
	 * returnValue 表示的是方法返回值
	 * method 被执行的方法
	 * agrs 表示执行方法参数
	 * target 被调用方法的目标对象
	 */
	@Override
	public void afterReturning(Object returnValue, Method method, Object[] agrs,
			Object target) throws Throwable {
		System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
		//返回被调用方法的返回值
		System.out.println("返回值"+returnValue);
	}
}

切入点

@Service(value="UserService")
public class UserServiceImp implements UserService {
	@Override
	public void add() {
		System.out.println("add====");		
	}
	@Override
	public String seach() {
		System.out.println("seach====");		
		return "seach";
	}
}

测试

@Test
	public void fun(){
		ApplicationContext app=new ClassPathXmlApplicationContext("applictionContext.xml");
		UserService ser = (UserService)app.getBean("UserService");
		ser.add();
		ser.seach();
	}
  1. 自定义通知(aopxml开发)
    applictionContext.xml
<!-- aop的xml的基本配置 -->
	<context:component-scan base-package="spring_aop_demo02.UserService"></context:component-scan>
	<bean id="proxy" class="spring_aop_demo02.proxy.proxy"></bean>
	<aop:config>
	<!-- 切入点的配置 -->
	<aop:pointcut expression="execution(* spring_aop_demo02.UserService.UserServiceImp.add(..))" id="pointcut1"/>
	<aop:pointcut expression="execution(* spring_aop_demo02.UserService.UserServiceImp.seach(..))" id="pointcut2"/>
	<aop:pointcut expression="execution(* spring_aop_demo02.UserService.UserServiceImp.update(..))" id="pointcut3"/>
	<aop:pointcut expression="execution(* spring_aop_demo02.UserService.UserServiceImp.delete(..))" id="pointcut4"/>
	<!--切面的配置  aspect 表示的是单个切面-->
	<aop:aspect ref="proxy">
	<!-- 为pointcut1切入点配置前置通知-->
	<aop:before method="before" pointcut-ref="pointcut1"/>
	<aop:after-returning method="afterreturn" pointcut-ref="pointcut2" returning="result"/>
	<aop:around method="around" pointcut-ref="pointcut3"/>
	<!-- 异常 -->
	<aop:after-throwing method="throwable" pointcut-ref="pointcut4"/>
	<!-- 最终通知after -->
	<aop:after method="after" pointcut-ref="pointcut4"/>
	</aop:aspect>
	</aop:config>

通知

public class proxy {
	public void before(){
		System.out.println("前置通知=======");
	}
//	这个地方的的result必须和前面的参数的返回值相同,才可以进行数据的返回
	public void afterreturn(Object result){
		System.out.println("后置通知=======" +"return"+result);
	}
	public void throwable(){
		System.out.println("异常通知=======");
	}
	public void around(ProceedingJoinPoint join) throws Throwable{
		System.out.println("环绕前通知=======");
		Object proceed = join.proceed();
		System.out.println("环绕后通知=======");
	}
	public void after(){
		System.out.println("最终通知=======");
	}
}

切入点

@Service(value="UserService")
public class UserServiceImp  implements UserService{
	@Value("123")
	private String result;
	@Override
	public void add() {
		System.out.println("add====");		
	}
	@Override
	public String seach() {
		System.out.println("seach====");		
		return this.result;
	}
	@Override
	public void delete() {
		//造成一个异常的出的出现
		int a=10/0;
	System.out.println("delete====");
	}
	@Override
	public void update() {
		System.out.println("update====");
	}
}
  1. AOP注解进行开发
    applictionContext.xml
<!--使用注解进行aop的配置  -->
	<!-- 在配置文件中开开启aop的注解开发 -->
	<aop:aspectj-autoproxy/>
	<bean id="user" class="spring_aop_demo01.Test.UserDao"></bean>
	<bean id="proxy" class="spring_aop_demo01.Test.proxy"></bean>

切入点

public class UserDao implements User {
	@Override
	public void save() {
		System.out.println("save");
	}
}

通知

public class proxy {
	@Before(value="execution( spring_aop_demo01.Test.UserDao.save(..))")
	public void before(){
		System.out.println("前置增强==========");
	}
}

如果觉得这样将切入点配置早通知这个位置,如果不是很好区分,还可以进行如下的配置,将通知设置名称,然后进行切入点的配置操作:如下

public class proxy {
//	aop的切面的配置操作
	//前置通知
	@Before(value="proxy.pointcut1()")
	public void before(){
		System.out.println("前置通知=======");
	}
//	后置通知
//	这个地方的的result必须和前面的参数的返回值相同,才可以进行数据的返回
	@AfterReturning(value="proxy.pointcut2()",returning="result")
	public void afterreturn(Object result){
		System.out.println("后置通知=======" +"return"+result);
	}
	//异常通知
	@AfterThrowing(value="proxy.pointcut3()", throwing="e")
	public void throwable(Throwable e){
		System.out.println("异常通知======="+e.getMessage());
	}
	//环绕通知
	@Around(value="proxy.pointcut4()")
	public Object around(ProceedingJoinPoint join) throws Throwable{
		System.out.println("环绕前通知=======");
		Object proceed = join.proceed();
		System.out.println("环绕后通知=======");
		return proceed;
	}
	//最终通知
	@After(value="proxy.pointcut3()")
	public void after(){
		System.out.println("最终通知=======");
	}
	
//	进行切入点的配置操作
	@Pointcut(value="execution( spring_aop_demo02.UserService.UserServiceImp.add(..))")
	private void pointcut1(){}
	@Pointcut(value="execution(* spring_aop_demo02.UserService.UserServiceImp.seach(..))")
	private void pointcut2(){}
	@Pointcut(value="execution(* spring_aop_demo02.UserService.UserServiceImp.delete(..))")
	private void pointcut3(){}
	@Pointcut(value="execution(* spring_aop_demo02.UserService.UserServiceImp.update(..))")
	private void pointcut4(){}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applictionContext2.xml")
public class Test {
	@Resource(name="user")
	private User user;
	@org.junit.Test
	public void fun(){
		user.save();
	}
}

Spring的JDBC的模板使用

Spring对持久层也提供了解决方案:ORM模块和JDBC的模板。
applictionContext_c3p0.xml

<!-- 在这里我们可以进行配置文件的抽取操作 -->
	<!-- 第一种引入的操作 将配置文件设置到location中来 -->
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location" value="classpath:jdbc.properties"></property>
	</bean>
	<!-- 第二种引入的操作context加载类目录下面的资源文件直接引入配置文件的中的指定位置-->
	<context:property-placeholder location="classpath:jdbc.properties"/>
	<!-- 将配置管理交给spring来进行管理操作 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="driverClass" value="${jdbc.driverClass}"></property>
	<property name="jdbcUrl" value="${jdbc.url}"></property>
	<property name="user" value="${jdbc.username}"></property>
	<property name="password" value="${jdbc.password}"></property>
	</bean>
	<!-- 创建jdbc模板 -->
	<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	<property name="dataSource" ref="dataSource"/>
	</bean>

DAO层

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applictionContext_c3p0.xml")
public class Test_c3p0_demo {
	@Resource(name="jdbctemplate")
	private JdbcTemplate jdbcTemplate;
	@Test
	public void fun() {
		String sql="insert account values(null,?,?)";
		jdbcTemplate.update(sql, "jree",400d);
	}

	//@Test//修改数据
	public void fun2() {
		String sql="update account set money=? where id=?";
		jdbcTemplate.update(sql,1000d,1);
	}
	
	//@Test//删除数据
	public void fun3() {
		String sql="delete from account where id=?";
		jdbcTemplate.update(sql,3);
	}
	@Test //进行数据的查询操作(查询一个属性值)
	public void fun4() {
		String sql="select name from account where id=?";
		String queryForObject = jdbcTemplate.queryForObject(sql, String.class,1);
		System.out.println(queryForObject);
	}
	@Test //统计查询 
	public void fun5() {
		String sql="select count(*) from account";
		Long count=jdbcTemplate.queryForObject(sql, Long.class);
		System.out.println(count);
	}
	@Test// 查询数据返回一个对象 使用jdbc模板的时候需要自己进行手动的存储数据到对象中
	public void fun6() {
		String sql="select *from account where id=?";
		Account acc=jdbcTemplate.queryForObject(sql, new MyRowMapper(),1);
		System.out.println(acc);
	}
	@Test// 查询数据返回一个一个集合数据
	public void fun7() {
		String sql="select *from account";
		List<Account> query = jdbcTemplate.query(sql, new MyRowMapper());
		for (Account account : query) {
			System.out.println(account.toString());
		}
	}
}
/*
 * 封装一个类的操作  这个地方就是让我们实现这个RowMapper
 * 这个接口里面的方法 将结果集封装到一个对象进行数据的返回
 * 这个地方如果是需要获取所有的数据的一个集合的话,可以实现一个res.next 
 * 角标查询的操作,将所有的数据都封装到一个集合中来
 */
class MyRowMapper implements RowMapper<Account>{
	@Override
	public Account mapRow(ResultSet res, int row) throws SQLException {
		Account acc=new Account();
		acc.setId(res.getInt("id"));
		acc.setName(res.getString("name"));
		acc.setMoney(res.getDouble("money"));
		return acc;
	}
}

Account .java 封装的3个属性,不用关心数据库的数据,主要是了解spring提供的JDBC模块的操作

	private int id ;
	private String name;
	private double money;

Spring事务的三种配置方式

  • 说到事务,在这里解释一下事务(逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败)
  1. 事务的特性4点:
    原子性:事务不可分割
    一致性:事务执行前后数据完整性保持一致
    隔离性:一个事务的执行不应该受到其他事务的干扰
    持久性:一旦事务结束,数据就持久化到数据库
  2. 安全性问题
    —读问题
    脏读 :一个事务读到另一个事务未提交的数据
    不可重复读:一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致 虚读、幻读:一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致。
    —写问题
    丢失更新
  3. 事务的隔离级别
    Read uncommitted :未提交读,任何读问题解决不了。
    Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。(mysql支持)
    Repeatable read :重复读,解决脏读和不可重复读,但是虚读有可能发生。(orcal)
    Serializable :解决所有读问题。
  • 下面介绍spring中事务的操作
  1. 平台事务管理器(PlatformTransactionManager):接口,是Spring用于管理事务的真正的对象。
    DataSourceTransactionManager:底层使用JDBC管理事务
    HibernateTransactionManager:底层使用Hibernate管理事务
  2. 定义事务信息(TransactionDefinition)
    用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读
  3. 事务状态(TransactionStatus)
    用于记录在事务管理过程中,事务的状态的对象
    关系:Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。
  4. 传播行为
  • Spring中提供了七种事务的传播行为:
    保证多个操作在同一个事务中
    PROPAGATION_REQUIRED :默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
    PROPAGATION_SUPPORTS:支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
    PROPAGATION_MANDATORY :如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。

  • 保证多个操作不在同一个事务中
    PROPAGATION_REQUIRES_NEW :如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
    PROPAGATION_NOT_SUPPORTED :如果A中有事务,将A的事务挂起。不使用事务管理。
    PROPAGATION_NEVER :如果A中有事务,报异常。

  • 嵌套式事务
    PROPAGATION_NESTED :嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。

第一种编程式事务

applictionContext.xml

<!--配置平台事务管理器============================= -->
	<bean id= "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
	</bean>
	<!--配置事务管理的模板========将平台事务管理其注入到配置管理器模板中-->
	<bean id="TransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
	<property name="transactionManager" ref="transactionManager"/>
	</bean> 

编写事务操作类

/**实现一个转账的操作(编写式事务)
	 * from 转账人
	 * to  收账人
	 * money  转账的金额
	 */
	@Override
	public void transfer(String from, String to, double money) {
		//函数式的编写事务配置方法 这个其实就是aop的技术
		this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {	
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				//from减少钱
				dao.outMoney(from,money);
				//to加钱
				//抛出一个异常
				//int a=10/0;
				dao.inMoney(to,money);	
			}
		});
		
	}
第二种声明式事务xml实现

applictionContext.xml

	<!--配置平台事务管理器============================= -->
	<bean id= "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
	</bean>
	<!-- 配置事务 的增强操作 =======-->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<!--事务管理的规则=========  -->
	<tx:attributes>
	<!-- 对name方法进行事务的添加  propagation表示是传递方式  isolation表示是隔离的状态 -->
	<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"/>
	</tx:attributes>
	</tx:advice>
	<!-- 配置aop切入点 -->
	<!--进行aop的配置 切入点配置 ===========-->
	<aop:config>
	<aop:pointcut expression="execution(* spring_jdbc_tx_demo02.UserService.Imp.UserServiceImp.*(..))" id="pointcut1"/>
	<!-- pointcut-ref事务的指定切入点配置   advice-ref="txAdvice" 配置切面-->
	<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
	</aop:config>

编写事务操作


	/**实现一个转账的操作(声明事务)
	 * from 转账人
	 * to  收账人
	 * money  转账的金额
	 */
	@Override
	public void transfer(String from, String to, double money) {
		//from减少钱
		userdao.outMoney(from,money);
		//to加钱
		//抛出一个异常
		//int a=10/0;
		userdao.inMoney(to,money);	
		
	}
第三种声明式事务注解开发

applictionContext.xml

<!--配置平台事务管理器============================= -->
	<bean id= "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
	</bean>
	<!-- 开启事务注解 声明-->
	<tx:annotation-driven transaction-manager="transactionManager"/>	

编写事务操作类

//注解开发
@Transactional(isolation =Isolation.DEFAULT,propagation = Propagation.REQUIRED)
public class UserServiceImp implements UserService {
	private UserDao dao;
	public void setDao(UserDao dao) {
		this.dao = dao;
	}
	/**实现一个转账的操作(声明式事务)
	 * from 转账人
	 * to  收账人
	 * money  转账的金额
	 */
	@Override
	public void transfer(String from, String to, double money) {
		//from减少钱
		dao.outMoney(from,money);
		//to加钱
		//抛出一个异常
		int a=10/0;
		dao.inMoney(to,money);	
	}
}

spring事务的配置就是通过的aop的思想进行实现的.

参考说明:黑马程序员资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值