Spring入门2:AOP编程

14 篇文章 0 订阅

1. Aop编程

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.
将重复代码抽离,整合成方法,通过代理对象将抽离的代码植入到应用到的需求方法中.

  ==应用:
Authentication 权限
Caching缓存
Context passing内容传递
Error handling 错误处理
Lazy loading 延时加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization性能优化
Persistence 持久化
Resource pooling资源池
Synchronization 同步

Transactions事务


2. Aop编程之静态代理

        //1. 业务接口
	public interface IUserDao {
		public abstract void save();
	}
	
	//2.业务实现
	@Repository
	public class UserDao implements IUserDao {
		@Resource
		private Aop aop;
		public void save(){
			aop.begin();//植入抽离的代码
			System.out.println("UserDao.save()");
			aop.commite();//植入抽离的代码
		}
	}
	
	//3. Aop,关注点代码
	@Component
	public class Aop {
		// 在执行业务方法之前执行
		public void begin(){
			System.out.println("--> 开启事务");
		}

		// 在执行业务方法之后执行
		public void commite(){
			System.out.println("--> 提交事务");
		}
	}
	
        // 4. bean.xml配置,开启注解扫描
	 <context:component-scan base-package="cn.aop.d_my_aop.."></context:component-scan>
	 // 5. 测试
	 public class Main {
		public static void main(String[] args) {
			ApplicationContext ac = new ClassPathXmlApplicationContext("bean2.xml",Main.class);
			IUserDao dao =  (IUserDao) ac.getBean("userDao");
			dao.save();
		}
	}

3. Aop编程之动态代理

        //1. 业务接口
	public interface IUserDao {
		public abstract void save();
	}
	
	//2. 业务实现
	@Repository
	public class UserDao implements IUserDao {
		public void save(){
			System.out.println("UserDao.save()");
		}
	}
	
	//3. 关注点代码
	@Component
	public class Aop {
		// 在执行业务方法之前执行
		public void begin(){
			System.out.println("--> 开启事务");
		}

		// 在执行业务方法之后执行
		public void commite(){
			System.out.println("--> 提交事务");
		}
	}
	
	//4.代理对象工厂类,为目标对象添加额外业务代码
	public class ProxyFactory {
		public static Object getProxyDao(final Object target, final Aop aop){
			return Proxy.newProxyInstance(
					target.getClass().getClassLoader(), target.getClass().getInterfaces(), 
					new InvocationHandler() {
						@Override
						public Object invoke(Object proxy, Method method, Object[] args)
								throws Throwable {
							
							//1. 执行关注点代码
							aop.begin();
							
							//2. 执行目标对象方法
							Object retrunValue = method.invoke(target, args);
							
							//2. 执行关注点代码
							aop.commite();
							
							return retrunValue;
						}
					});
		}
	}
	//5. bean.xml配置
	 <context:component-scan base-package="cn.aop.d_my_aop2.."></context:component-scan>
	
	 <!-- 通过工厂的静态方法生成代理对象! -->
	 <bean id="factory_user" class="cn.aop.d_my_aop2.ProxyFactory" factory-method="getProxyDao">
	 	<constructor-arg ref="userDao"></constructor-arg>
	 	<constructor-arg ref="aop"></constructor-arg>
	 </bean>
	 //6. 测试
	 public class Main {
		public static void main(String[] args) {
			ApplicationContext ac = new ClassPathXmlApplicationContext("bean2.xml",Main.class);
			IUserDao dao =  (IUserDao) ac.getBean("factory_user");
			dao.save();
		}
	}

4. Aop编程之注解实现

	//1. 目标对象接口
	public interface IUserDao {
		public abstract void save();
		public abstract void get();
	}
	
	//2. 目标对象实现
	@Repository
	public class UserDao implements IUserDao {
		public void save(){
			System.out.println("UserDao.save()");
		}
		public void get() {//int i=1/0;
			System.out.println("UserDao.get()");
		}
	}
	
	@Repository
	public class OrderDao {
		public  void save(){
			System.out.println("OrderDao.save()");
		}
		public void get() {
			System.out.println("OrderDao.get()");
		}
	}
	
	//3. Aop关注代码注入
	/**
	 * Aop执行流程:
	 * 1. IOC容器会根据切入点表达式的规则,符合规则的目标对象(放入容器的对象),从而生成代理对象! 
	 * 2. 如果目标对象有实现接口,用JDK代理
	 *    如果目标对象没有实现接口,使用Cglib代理!
	 * 3. 用户从容器获取对象
	 *    (如果对象是多例,再看是否切入点表达式规则,如果符合就生成代理对象!)
	 * 4. 执行代理对象的方法时候,
	 * 		# 那么通过代理对象调用目标对象
	 * 		# 在目标方法上,动态织入切面类中的代码!
	 * 
	 *
	 */
	@Aspect   // 指定当前类为切面类
	@Component
	public class Aop {
		
		// 定义一个切入点表达式,供其他方法引用这个表达式!
		@Pointcut("execution(* cn.aop.e_aop.*.*(..))")
		public void pt(){
		}

		// 切入点表达式,指定给哪些类生成代理对象!
		// 在执行业务方法之前执行
		@Before("pt()")
		public void begin(){
			System.out.println("-->【前置通知】 开启事务");
		}

		// 在业务方法执行之后执行!  (无论目标方法时候有异常,都会执行!)
		@After("pt()")
		public void commite(){
			System.out.println("-->【后置通知】 提交事务");
		}
		
		// 在目标方法出现异常时候执行
		@AfterThrowing("pt()")
		public void afterThrowing(){
			System.out.println("【异常通知】");
		}
		
		// 返回后通知, 在执行目标方法正常结束后执行!
		@AfterReturning("pt()")
		public void afterReturning(){
			System.out.println("【返回后通知!】");
		}
		
		//环绕目标方法执行
		@Around("pt()")
		public void around(ProceedingJoinPoint pjp) throws Throwable{
			System.out.println("【环绕前】");
			pjp.proceed();  // 执行目标对象方法
			System.out.println("【环绕后】");
		}
	}
	//4. bean.xml配置
		<!-- 开启注解扫描 -->
	<context:component-scan base-package="cn.aop.e_aop"></context:component-scan>
	<!-- 开启Aop注解 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
	//5. 测试
	public class App {
	
		private ApplicationContext ac = 
			new ClassPathXmlApplicationContext("bean.xml",App.class);

		// Jdk代理
		@Test
		public void testApp() throws Exception {
			IUserDao userDao = (IUserDao) ac.getBean("userDao");
			System.out.println(userDao.getClass());   // $Proxy13 implements IUserdao
			userDao.get();  //(动态织入通知代码!)
		}
		
		// Cglib代理
		@Test
		public void testApp2() throws Exception {
			OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
			System.out.println(orderDao.getClass());   //OrderDao$$EnhancerByCGLIB$$5b49cfee  
			orderDao.get();
		}
		
		/*
		 *  注意:
		 *     如果目标对象有实现接口,必须用接口接收!否则:
		 *     java.lang.ClassCastException: 
		 *          $Proxy13 cannot be cast to cn.aop.e_aop.UserDao
		 *          
		 *     为什么?
		 *         代理是通过实现接口完成的!需要用接口引用接收!
		 */
		@Test
		public void testApp3() throws Exception {
			// 报错!!!!!!!
			UserDao userDao = (UserDao) ac.getBean("userDao");
			System.out.println(userDao.getClass());   // $Proxy13
			userDao.get();
		}
	}
	 

5. Aop编程之XML配置实现

        //1. 目标对象接口
	public interface IUserDao {
		public abstract void save();
		public abstract void get();
	}
	
	//2. 目标对象
	public class UserDao implements IUserDao {
		public void save(){
			System.out.println("UserDao.save()");
		}
		@Override
		public void get() {//int i=1/0;
			System.out.println("UserDao.get()");
		}
	}
	
	public class OrderDao {
		public  void save(){
			System.out.println("OrderDao.save()");
		}
		public void get() {
			System.out.println("OrderDao.get()");
		}
	}
	
	//3. Aop切面类,关注点代码
	public class Aop {
		public void begin(){
			System.out.println("-->【前置通知】 开启事务");
		}

		public void commite(){
			System.out.println("-->【后置通知】 提交事务");
		}
		
		public void afterThrowing(){
			System.out.println("【异常通知】");
		}
		
		public void afterReturning(){
			System.out.println("【返回后通知!】");
		}
		
		public void around(ProceedingJoinPoint pjp) throws Throwable{
			System.out.println("【环绕前】");
			pjp.proceed();  // 执行目标对象方法
			System.out.println("【环绕后】");
		}
	}
	//4. bean.xml配置
	<!-- 把对象加入IOC容器 -->
	<bean id="userDao" class="cn.aop.f_aop_xml.UserDao"></bean>
	<bean id="orderDao" class="cn.aop.f_aop_xml.OrderDao"></bean>
	
	<!-- 
		【XML方式实现AOP编程】
	 -->
	 
	 <!-- 实例化切面类 -->
	 <bean id="aop" class="cn.aop.f_aop_xml.Aop"></bean>
	 
	 <!-- Aop配置 -->
	 <aop:config>
	 	<aop:aspect ref="aop">
	 		<!-- 定义一个切入点表达式 -->
	 		<aop:pointcut expression="execution(* cn.aop.f_aop_xml.*.*(..))" id="pt"/>
	 	
	 		<!-- 环绕通知 -->
	 		<aop:around method="around" pointcut-ref="pt"/>
	 		
	 		<!-- 前置通知 -->
	 		<aop:before method="begin" pointcut-ref="pt"/>
	 		
	 		<!-- 后置通知 -->
	 		<aop:after method="commite" pointcut-ref="pt"/>
	 		
	 		<!-- 异常通知 -->
	 		<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
	 		
	 		<!-- 返回后通知 -->
	 		<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
	 	</aop:aspect>
	 </aop:config>

         //5. 测试
	 public class App {
		private ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml",App.class);

		// Jdk代理
		@Test
		public void testApp() throws Exception {
			IUserDao userDao = (IUserDao) ac.getBean("userDao");
			System.out.println(userDao.getClass());   // $Proxy13 implements IUserdao
			userDao.get();  //(动态织入通知代码!)
		}
		
		// Cglib代理
		@Test
		public void testApp2() throws Exception {
			OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
			System.out.println(orderDao.getClass());   //OrderDao$$EnhancerByCGLIB$$5b49cfee  
			orderDao.get();
		}
	}

6.Cglib代理

        也叫,子类代理,是在运行时在内存中动态生成的代理对象.

a.目标对象不需要实现接口,
b.目标对象不能为final,否则保存,
c.目标对象的方法不能为final/static,否则不会被拦截,也不会被代理对象调用.

d.要额外引入jar包支持Cglib代理.在spring3.2中,spring核心包已经包含了这个功能.

        // 1. 目标对象
	public  class UserDao  {
		public static void save() {
			System.out.println("保存用户!");
		}
		public void get() {
			System.out.println("get...");
		}
	}
	
	// 2. 代理对象类,实现MethodInterceptor接口
	public class BeanFactory implements MethodInterceptor{
		// 1).目标对象
		private Object target;
		public BeanFactory(Object target){//构造函数,初始化目标对象
			this.target = target;
		}
		// 2).为目标对象生成代理对象
		public Object getProxy(){
			//a.创建字节码工具类对象
			Enhancer en = new Enhancer();
			//b.设置父类
			en.setSuperclass(target.getClass());
			//c.设置回调函数
			en.setCallback(this);
			//创建代理对象
			return en.create();
		}
		@Override
		public Object intercept(Object obj, Method method, Object[] args,
				MethodProxy methodProxy) throws Throwable {
			System.out.println("开始事务!");
			Object returnValue = method.invoke(target, args);  // 执行目标对象的方法
			System.out.println("提交事务!");
			return returnValue;
		}
	}
	
	// 3. 测试
	public class App {
		public static void main(String[] args) {
			//1. 目标对象
			UserDao target = new UserDao();
			System.out.println(target.getClass());
			
			//2. 代理对象   
			UserDao proxy = (UserDao) new BeanFactory(target).getProxy();
			System.out.println(proxy.getClass());
			
			//3. 执行代理对象,方法
			proxy.save();
		}
	}

7.Aop编程之切入点表达式

        <!-- Aop配置 :关注点表达式 -->
	 <aop:config>
	 	<aop:aspect ref="aop">
	 		<!-- 定义一个切入点表达式, 规则: -->
	 	
	 		<!-- 1. 拦截指定类的指定的方法,方法的参数列表任意! -->
	 		<!--<aop:pointcut expression="execution(* cn.aop.g_pointcut.UserDao.get(..))" id="pt"/>-->
	 		
	 		<!-- 2. 拦截指定类的所有的方法 -->
	 		<!--<aop:pointcut expression="execution(* cn.aop.g_pointcut.UserDao.*(..))" id="pt"/>-->
	 	
	 		<!-- 3. 拦截指定包下所有类的方法 -->
	 		<!--<aop:pointcut expression="execution(* cn.aop.g_pointcut.*.*(..))" id="pt"/>-->
	 		
	 		<!-- 4. 拦截指定的包,及其子包下所有类的方法 -->
	 		<!--<aop:pointcut expression="execution(* cn..*Service.*(..))" id="pt"/>-->
	 
	 		<!-- 5. 拦截任意public方法 -->
	 		<!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>-->
	 		
	 		<!-- 6. 拦截指定的方法 -->
	 		<!--<aop:pointcut expression="execution(* save())" id="pt"/>-->
	 		
	 		<!-- 7. 拦截指定的以Dao结尾的bean -->
	 		<!--<aop:pointcut expression="bean(*Dao)" id="pt"/>-->
	 		
	 		<!-- 8. 拦截以save或get开头的方法 -->
	 		<!--<aop:pointcut expression="execution(* get*()) || execution(* save*())" id="pt"/>-->
	 		<!--<aop:pointcut expression="execution(* get*()) or execution(* save*())" id="pt"/>-->
	 	
	 		<!-- 9. 且 -->
	 		<!--<aop:pointcut expression="execution(* get*()) and execution(* save*())" id="pt"/>-->
	 		<!--<aop:pointcut expression="execution(* get*()) && execution(* save*())" id="pt"/>-->
	 		
	 		<!-- 10. 不拦截get方法 -->
	 		<!--<aop:pointcut expression="!execution(* get*())" id="pt"/>-->
	 		<aop:pointcut expression=" not execution(* get*())" id="pt"/>
	 		
	 		<!-- 环绕通知 -->
	 		<aop:around method="around" pointcut-ref="pt"/>
	 		<!-- 前置通知 -->
	 		<aop:before method="begin" pointcut-ref="pt"/>
	 	</aop:aspect>
	 </aop:config>
	 
	


*若有不足或错误,请多多指教,谢谢!*








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值