javaee之Spring的AOP案例

学习Spring的知识,需要学习的是IOC思想和AOP思想,之前学习了IOC,就是控制反转,在IOC中也可以进行依赖注入的方式
学习控制反转就是学习在容器对一个对象的创建。


在学习AOP切面编程,所谓aop就是类似过滤器和拦截器的思想,实现对一些业务代码、服务代码的分离,用来降低服务代码和业务代码的耦合性


实现AOP的方式主要采用的是代理模式,分为:静态代理模式、动态代理模式和cglib子类代理模式


①。静态代理:
/**
 * 代理类: 用于切入服务代码(事务代码)
 * @author APPle
 *
 */
public class UserDaoProxyImpl implements IUserDao {
	private IUserDao userDao;
	//获取或创建被代理类对象
	public UserDaoProxyImpl(IUserDao userDao){
		this.userDao = userDao;
	}
	
	@Override
	public void save() {
		System.out.println("开启事务");
		//调用核心业务方法
		userDao.save();
		System.out.println("提交事务");
	}


}



采用静态代理的特点:
必须实现和被代理类相同的接口,绑定指定的接口,扩展性和通用性不好



②动态代理模式:
	/**
 * 用于生成代理类的工厂类
 * @author APPle
 *
 */
public class ProxyBeanFactory {
	private Object target;
	/**
	 * 绑定被代理类对象
	 * target: 需要生成代理类对象的被代理
	 */
	public void bind(Object target){
		this.target = target;
	}


	/**
	 * 获取需要生成的代理类对象
	 */
	public Object getProxy(){
		/**
		 * jdk动态代理:利用jdk的工具类生成代理类对象
		 *     java.lang.reflect.Proxy类:
		 *     
		 *     static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
 					
		 */
		Object proxy = 
				Proxy.newProxyInstance(
						target.getClass().getClassLoader(), // 类加载器(没有特定要求)
						target.getClass().getInterfaces(), //需要指定实现的代理接口(通常和被代理类相同的接口)
						new InvocationHandler(){// 代理完之后需要做什么??(需要提供InvocationHandler的实现类)
							//invoke: 代理类调用的每个方法
							/**
							 * proxy: 代理类对象
							 * method: 方法对象
							 * args: 方法传入的参数
							 * 返回值:方法调用后返回的值
							 */
							@Override
							public Object invoke(Object proxy, Method method,
									Object[] args) throws Throwable {
								//System.out.println("调用了代理类的方法:"+method.getName());
								
								System.out.println("开启事务");
								
								//调用被代理类对象的核心业务代码
								Object result =  method.invoke(target, args);
								
								System.out.println("提交事务");
								
								return result;
							}
						} 
						);
		return proxy;
	}
	
}


采用动态代理的特点:
可以生成任何接口的代理类,通用性比较好,但是也是必须依赖接口,没有接口也是不能使用动态代理


③Cglib子类代理
	/**
 * 用于生成子类的代理类的工厂类
 * @author APPle
 *
 */
public class ProxyBeanFactory{
	private Object target;
	/**
	 * 绑定被代理类对象
	 * target: 需要生成代理类对象的被代理
	 */
	public void bind(Object target){
		this.target = target;
	}


	/**
	 * 获取需要生成的代理类对象
	 */
	public Object getProxy(){
		//1.创建工具类
		Enhancer enhancer = new Enhancer();
		//2.*指定父类(被代理类对象的类型)
		enhancer.setSuperclass(target.getClass());
		//3.指定回调函数(代理完后需要做什么?)
		enhancer.setCallback(new MethodInterceptor() {
			@Override
			public Object intercept(Object proxy, Method method, Object[] args,
					MethodProxy arg3) throws Throwable {
				
				System.out.println("开启事务");
				
				//调用目标对象的核心业务方法
				Object result = method.invoke(target, args);
				
				System.out.println("结束事务");
				
				return result;
			}
		});
		//4.生成子类代理对象
		return enhancer.create();
	}
}



特点是代理类无需实现任何的接口


而使用Spring的AOP,所需要的是设置四个元素:
JoinPoint:连接点,一般为目标对象的每个方法
PontCut:切入点,切入了服务代码的连接点
Advice:通知:在切入点上面需要切入的服务代码
Aspect:切面:在指定的切入点切入指定的通知形成切面

package gz.itcast.dao;


import org.aspectj.lang.ProceedingJoinPoint;


/**
 * 定义切面类
 * @author APPle
 *
 */
public class MyAspect {


	/**
	 * 常用的通知类:
	 *   前置通知: 在目标对象的连接点之前调用
	 *   后置通知:在目标对象的连接点之后调用
	 *   环绕通知: 在目标对象的连接点之前与之后调用
	 */
	//定义前置通知
	public void before(){
		System.out.println("开启事务");
	} 
	
	//定义后置通知
	public void after(){
		System.out.println("提交事务");
	}
	
	//环绕通知
	public void round(ProceedingJoinPoint jp) throws Throwable{
		System.out.println("环绕通知前面代码");
		
		//执行目标对象的核心方法
		jp.proceed();//执行连接点方法
		
		System.out.println("环绕通知后面代码");
	}
}

	<!-- 1.创建目标对象 -->
	<bean id="userDao" class="gz.itcast.dao.UserDao"></bean>
	
	<!-- 2.创建切面类对象 -->
	<bean id="myaspect" class="gz.itcast.dao.MyAspect"></bean>


	<!-- 3.配置切面 -->
	<aop:config>
		<!-- 切面 
		ref: 关联切面类对象
		-->
		<aop:aspect ref="myaspect">
				<!-- 3.1 切入点 
					id: 切入点的别名
					expression: 切入点表达式 :格式: execution(修饰符 方法的返回值类型 方法名(包+类)(方法中参数列表)) 
				-->
				<aop:pointcut expression="execution(* save*(..))" id="mypt"/>
				<!-- 3.2 通知 -->
				<!-- 前置通知
				method: 切面类中的前置通知的方法名称
				pointcut-ref: 需要关联的切入点
				 -->
				<aop:before method="before" pointcut-ref="mypt"/>
				<aop:after method="after" pointcut-ref="mypt"/>
				<aop:around method="round" pointcut-ref="mypt"/>
		</aop:aspect>
	</aop:config>
	
	
	<!-- 切换spring底层代理类生成机制
	false : 有接口的情况下使用jdk动态代理
	true: 强制使用cglib生成代理类对象
	 -->
	<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>	



在applicationContext.xml中的切面配置通知的类型:前置通知、后置通知和环绕通知
①前置通知(在目标对象的连接点之前就调用切面类)
<aop:before method="before" pointcut-ref="mypt"/>


②后置通知(在目标对象的连接点之后就调用切面类)
<aop:after method="after" pointcut-ref="mypt"/>

③环绕通知(在目标对象的连接点之前和之后就调用切面类)
	//环绕通知
	public void round(ProceedingJoinPoint jp) throws Throwable{
		System.out.println("环绕通知前面代码");
		
		//执行目标对象的核心方法
		jp.proceed();//执行连接点方法
		
		System.out.println("环绕通知后面代码");
	}


<aop:around method="round" pointcut-ref="mypt"/>


基本的aop主要是用来比如整合持久层的时候,采用来切面事务管理
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值