JavaWeb——SpringAOP

  1. AOP
  2. Java动态代理
  3. cglib代理
  4. 配置AOP
  5. Spring管理事务

一、AOP

通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

二、Java动态代理

通过接口来实现接口

package beer.onexone.JavaProxy;

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

//用户自定义的动态代理类
public class MyInvocation implements InvocationHandler{

	//设置一个属性  代理对象
	private Object object;
	//创建代理类必须要有一个代理对象
	public MyInvocation(Object object) {
		this.object = object;
	}
	//创建代理对象的方法
	public Object createProxyInstance(){
		//代理类 创建代理对象的方法  
		//参数:根类加载器   该类的接口 动态代理类
		Object obj = Proxy.newProxyInstance(object.getClass().getClassLoader(),
				object.getClass().getInterfaces(), this);
		return obj;
	}
	@Override
	public Object invoke(Object obj, Method method, Object[] args)
			throws Throwable {
		//在被代理对象的方法执行前执行的
		System.out.println("前置的方法...");
		long oldTime = System.currentTimeMillis();
		//被代理对象开始执行方法
		Object invoke = method.invoke(this.object, args);
		//在被代理对象的方法执行后执行的
		long time = System.currentTimeMillis() - oldTime;
		System.out.println("后置的方法");
		System.out.println("总共用时:"+time+" 毫秒!");
		return invoke;
	}
	
}

三、cglib代理

通过继承被代理类来实现代理

package beer.onexone.cglibProxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


//创建一个cglib代理类
public class MyCglibProxy implements MethodInterceptor{
	//创建一个被代理对象
	private Object object;
	//添加一个构造方法 确保创建代理类有被代理对象传入
	public MyCglibProxy(Object object) {
		this.object = object;
	}
	//创建一个方法 创建代理类的方法
	public Object createProxyInstance(){
		//创建一个cglib的主类
		Enhancer en = new Enhancer();
		//设置被继承关系  设置被代理对象
		en.setSuperclass(object.getClass());
		//设置代理接口
		en.setCallback(this);
		//创建代理并返回
		return en.create();
	}
	//实现代理的方法
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		//在被代理对象的方法执行前执行的
		System.out.println("前置的方法...");
		long oldTime = System.currentTimeMillis();
		//被代理对象开始执行方法
		Object invoke = proxy.invokeSuper(obj, args);
		//在被代理对象的方法执行后执行的
		long time = System.currentTimeMillis() - oldTime;
		System.out.println("后置的方法");
		System.out.println("总共用时:"+time+" 毫秒!");
		return invoke;
	}
	
}

四、Spring配置AOP

AOP名词:

  • 连接点Joinpoint
    在目标对象中所有可以增强的方法
  • 切入点Pointcut
    目标对象已经增强的方法
  • 通知/增强Advice
    需要在目标方法中加强的代码
  • 目标对象Target
    具体被代理第对象
  • 引介Introduction
    引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能。
  • 织入Weaving
    将通知/增强添加到切入点的过程
  • 代理Proxy
    通知目标对象后创建的类
  • 切面Aspect
    切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。

使用XML配置:

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.1.xsd 
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.1.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.1.xsd ">
	
<!-- 将需要被代理的对象(目标对象)添加到容器 -->
<bean id="targrtProxy" class="beer.onexone.dao.impl.ProxyDemoImpl"></bean>
	<!-- 将通知类配置到容器 -->
	<bean id="advice" class="beer.onexone.advice.Advices"></bean>
	
	<!-- 进行AOP设置 -->
	<aop:config>
	<!-- 配置切面 切面表达式-->
<aop:pointcut  id="pointA"	expression="execution(* beer.onexone.dao.*.*(..))"></aop:pointcut>		
<!-- 指定通知类 -->
<!-- 指定使用通知类 -->
		<aop:aspect ref="advice">
			<!-- 配置前置通知 -->
			<aop:before method="before" pointcut-ref="pointA"/>
			<!-- 配置后置通知 出现异常不运行 -->
		<aop:after-returning method="atterSuccess" pointcut-ref="pointA"/>
			<!-- 环绕通知 -->
			<aop:around method="around" pointcut-ref="pointA"/>
		<!-- 	异常通知 -->
			<aop:after-throwing method="wentWrong" pointcut-ref="pointA"/>
			<!-- 后置通知 出现异常继续运行 -->
			<aop:after method="afterWrong" pointcut-ref="pointA"/> 
		</aop:aspect>
	
	</aop:config>
</beans>

通知类:

package beer.onexone.advice;

import org.aspectj.lang.ProceedingJoinPoint;

public class Advices {
			public void before() {
				System.out.println("前置通知");
			}
			public void atterSuccess() {
				System.out.println("成功后置通知");
			}
			public void around(ProceedingJoinPoint joinPoint) throws Throwable {
				System.out.println("环绕前通知");
				@SuppressWarnings("unused")
				Object object = joinPoint.proceed();
				System.out.println("环绕后通知");
			}
			public void afterWrong() {
				System.out.println("异常后置通知");
			}
			public void wentWrong() {
				System.out.println("异常通知");
			}
}

持久层方法:

package beer.onexone.dao;

public interface ProxyDemo {
					public void test();
					}
package beer.onexone.dao.impl;

import org.springframework.stereotype.Repository;

import beer.onexone.dao.ProxyDemo;

@Repository
public class ProxyDemoImpl implements ProxyDemo {

	@Override
	public void test() {
		System.out.println("被代理类运行");
	}
}

测试方法:

package beer.onexone.controller;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import beer.onexone.dao.ProxyDemo;
import beer.onexone.dao.impl.ProxyDemoImpl;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class DoProxy {
	@Autowired
	ProxyDemo demoImpl ;
			@Test
			public void test() {
				demoImpl.test(); 
			}
}

使用注解的配置

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.1.xsd 
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.1.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.1.xsd ">
	
<!-- 使用注释依赖注入 -->
	<context:annotation-config/>
	<!-- 添加包扫描 -->
	<context:component-scan base-package="beer.onexone"/>
	<!-- 添加aop的扫描 -->
	<aop:aspectj-autoproxy/>
	
</beans>

通知类

package beer.onexone.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

//添加到包扫描,标识为通知类
@Component
@Aspect
public class AdvicesAt {
			
			//标识切面表达式的类
			@Pointcut("execution(* beer.onexone.dao.*.*(..))")
			public void pointcut() {}
			
			//前置通知,可以写完全的切面表达式
			@Before("execution(* beer.onexone.dao.*.*(..))")
			public void before() {
				System.out.println("前置通知");
			}
			
			//后置成功通知,用类名加方法名
			@AfterReturning("AdvicesAt.pointcut()")
			public void atterSuccess() {
				System.out.println("成功后置通知");
			}
			
			//环绕通知
			@Around("AdvicesAt.pointcut()")
			public void around(ProceedingJoinPoint joinPoint) throws Throwable {
				System.out.println("环绕前通知");
				@SuppressWarnings("unused")
				Object object = joinPoint.proceed();
				System.out.println("环绕后通知");
			}
			
			//错误后置通知,一定会运行
			@After("AdvicesAt.pointcut()")
			public void afterWrong() {
				System.out.println("异常后置通知");
			}
			
			//错误通知
			@AfterThrowing("AdvicesAt.pointcut()")
			public void wentWrong() {
				System.out.println("异常通知");
			}
			
}

持久层

package beer.onexone.dao;

public interface ProxyDemo {
					public void test();
					}
package beer.onexone.dao.impl;

import org.springframework.stereotype.Repository;

import beer.onexone.dao.ProxyDemo;

@Repository
public class ProxyDemoImpl implements ProxyDemo {

	@Override
	public void test() {
		System.out.println("被代理类运行");
	}

}

测试方法

package beer.onexone.controller;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import beer.onexone.dao.ProxyDemo;
import beer.onexone.dao.impl.ProxyDemoImpl;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContextAt.xml")
public class DoProxyAt {
	@Autowired
	ProxyDemo demoImpl ;
			@Test
			public void test() {
				demoImpl.test(); 
			}
}

五、Spring管理事务

配置中事务的传播级别

@Transactional(propagation=Propagation.REQUIRED)
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
xml配置的内容:

XML配置事务

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans" 
	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-4.1.xsd 
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.1.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.1.xsd 
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-4.1.xsd ">
	
	<!-- 使用注释依赖注入 -->
	<context:annotation-config/>
	<!-- 添加包扫描 -->
	<context:component-scan base-package="beer.onexone"/>
		<!-- 添加aop的扫描 -->
	<aop:aspectj-autoproxy/>
	
	<!-- JDBC连接池 -->
	<bean id ="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
		<property name="url" value="jdbc:mysql:///spring"></property>
		<property name="username" value="root"></property>
		<property name="password" value="Qwertyuiop852963"></property>
	</bean> 
	
<!-- jdbcTmplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 添加一个事务管理平台spring官方自带 -->
	<bean id="transactionManager" 
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置事务 属性  方法  隔离级别  传播特性  是否只读 -->
	<tx:advice id="adviceTX" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="tr*"  propagation="REQUIRED" read-only="false"/>
			<tx:method name="get*"  propagation="NOT_SUPPORTED" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- 将事务配置到项目中 -->
<aop:config>
	<!-- 配置切面 切面表达式-->
<aop:pointcut  id="pointA"	expression="execution(* beer.onexone.dao.*.*(..))"></aop:pointcut>		
<!-- 将事务插入项目 -->
		<aop:advisor advice-ref="adviceTX" pointcut-ref="pointA"/>
	</aop:config>
	</beans>

持久层

package beer.onexone.dao;

import beer.onexone.beans.User;

public interface A2b {
				void trMony(User or,User to,double money);
				User getUser(int id);
}
package beer.onexone.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import beer.onexone.beans.User;
import beer.onexone.dao.A2b;

@Repository
public class A2bImpl implements A2b {

	@Autowired
	JdbcTemplate  jdbcTemplate;
	String sql;
	
	@Override
	public void trMony(User or,User to,double money) {
		sql = "update bank set money = money - ? where id = ?";
		int i = jdbcTemplate.update(sql,money,or.getId());
		
		sql = "update bank set money = money + ? where id = ?";
		int j = jdbcTemplate.update(sql,money,to.getId());

	}

	@Override
	public User getUser(int id) {
		sql="select * from bank where id = ?";
		return jdbcTemplate.queryForObject(sql, new RowMapper<User>() {
			@Override
			public User mapRow(ResultSet resultSet, int i) throws SQLException {
				User user = new User(resultSet.getInt("id"), resultSet.getString("b_name"), resultSet.getDouble("money"));
				return user;
			}},id);
	}

}

服务层

package beer.onexone.service;

import beer.onexone.beans.User;

public interface TrSerivice {
	void trMony(User or,User to,double money);
	User getUser(int id);
}
package beer.onexone.service.Impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import beer.onexone.beans.User;
import beer.onexone.dao.A2b;
import beer.onexone.service.TrSerivice;

@Service
public class TrSeriviceImpl implements TrSerivice {
	
@Autowired
A2b a2b;

@Override
public void trMony(User or, User to, double money) {
	 a2b.trMony(or, to, money);
}

@Override
public User getUser(int id) {
	return a2b.getUser(id);
}


}

控制层

package beer.onexone.controller;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import beer.onexone.beans.User;
import beer.onexone.service.TrSerivice;

@Controller
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContextTr.xml")
public class BankTr {
		@Autowired
		TrSerivice trSerivice;
		
		@Test
		public void testTr() throws Exception {
			User or = new User();
			or.setId(1);
			User to = new User();
			to.setId(2);
			trSerivice.trMony(or, to, 100.00);
		}
		@Test
		public void testGet() throws Exception {
			User user = trSerivice.getUser(2);
			System.out.println(user);
		}
}

使用注解配置事务

XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans" 
	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-4.1.xsd 
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.1.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.1.xsd 
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-4.1.xsd ">
	
	<!-- 使用注释依赖注入 -->
	<context:annotation-config/>
	<!-- 添加包扫描 -->
	<context:component-scan base-package="beer.onexone"/>
	<!-- 读取prop文件 -->
	<context:property-placeholder location="classpath:db.properties"/>
	
	<!-- c3p0的配置 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${driverClass}"/>
		<property name="jdbcUrl" value="${jdbcUrl}"></property>
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<!-- 初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
		<property name="initialPoolSize" value="${initialPoolSize}"/>
		<!-- 连接池中保留的最小连接数。 -->
		<property name="minPoolSize" value="${minPoolSize}"/>	
		<!-- 连接池中保留的最大连接数。Default: 15 -->
		<property name="maxPoolSize" value="${maxPoolSize}"/>
		<!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
		<property name="maxIdleTime" value="${maxIdleTime}"/>	
		<!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
		<property name="acquireIncrement" value="${acquireIncrement}"/>	
		<!-- 每60秒检查所有连接池中的空闲连接。Default: 0 -->
		<property name="idleConnectionTestPeriod" value="${idleConnectionTestPeriod}"/>
	</bean>
	
	<!-- jdbctmplate -->
	<bean id="jTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 添加一个事务管理平台spring官方自带 -->
	<bean id="transactionManager" 
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 使用注解配置事务开启 -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>
</beans>
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///spring
initialPoolSize=2
minPoolSize=1
maxPoolSize=10
maxIdleTime=600
acquireIncrement=2
idleConnectionTestPeriod=600

持久层

package beer.onexone.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import beer.onexone.beans.User;
import beer.onexone.dao.A2bAt;

@Repository
public class A2bImplAt implements A2bAt{

	@Autowired
	JdbcTemplate  jdbcTemplate;
	String sql;
	
	@Override
	public void trMony(User or,User to,double money) {
		sql = "update bank set money = money - ? where id = ?";
		int i = jdbcTemplate.update(sql,money,or.getId());
		
		sql = "update bank set money = money + ? where id = ?";
		int j = jdbcTemplate.update(sql,money,to.getId());

	}

	@Override
	public User getUser(int id) {
		sql="select * from bank where id = ?";
		return jdbcTemplate.queryForObject(sql, new RowMapper<User>() {
			@Override
			public User mapRow(ResultSet resultSet, int i) throws SQLException {
				User user = new User(resultSet.getInt("id"), resultSet.getString("b_name"), resultSet.getDouble("money"));
				return user;
			}},id);
	}

}
package beer.onexone.dao;

import beer.onexone.beans.User;

public interface A2bAt {
				void trMony(User or,User to,double money);
				User getUser(int id);
}

服务层

package beer.onexone.service.Impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import beer.onexone.beans.User;
import beer.onexone.dao.A2bAt;
import beer.onexone.service.TrSeriviceAt;

@Service
public class TrSeriviceImplAt implements TrSeriviceAt {
	
@Autowired
A2bAt a2b;

@Override
@Transactional
public void trMony(User or, User to, double money) {
	 a2b.trMony(or, to, money);
}

@Override
public User getUser(int id) {
	return a2b.getUser(id);
}
}
package beer.onexone.service;

import beer.onexone.beans.User;

public interface TrSeriviceAt {
	void trMony(User or,User to,double money);
	User getUser(int id);
}

控制层

package beer.onexone.controller;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import beer.onexone.beans.User;
import beer.onexone.service.TrSeriviceAt;

@Controller
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContextTrAt.xml")
public class BankTrAt {
		@Autowired
		TrSeriviceAt trSerivice;
		
		@Test
		public void testTr() throws Exception {
			User or = new User();
			or.setId(1);
			User to = new User();			to.setId(2);
			trSerivice.trMony(or, to, 100.00);
		}
		@Test
		public void testGet() throws Exception {
			User user = trSerivice.getUser(2);
			System.out.println(user);
		}
}

jingsongchan

发表评论

电子邮件地址不会被公开。 必填项已用*标注