Spring-----AOP

底层原理

JDK动态代理

                jdk代理必须是实现了接口的类         

public interface UserDao {
	public void save();
	public void update();
	public void find();
	public void delete();
}

 

public class UserDaoImpl implements UserDao {
	@Override
	public void save() {
		System.out.println("保存用户");
	}

	@Override
	public void update() {
		System.out.println("修改用户");
	}

	@Override
	public void find() {
		System.out.println("查询用户");
	}

	@Override
	public void delete() {
		System.out.println("删除用户");
	}
}

               代理类

public class JdkProxy implements InvocationHandler{

	//将要增强的对象传递到代理中
	private UserDao userDao;
	public JdkProxy(UserDao userDao){
		this.userDao = userDao;
	}
	
	/**
	 * 产生UserDao代理的方法
	 * @return
	 */
	public UserDao createProxy(){
		
		UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
		return userDaoProxy;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//判断方法名是不是save
		if("save".equals(method.getName())){
			System.out.println("权限校验");
		}
		return method.invoke(userDao, args);
	}
}

 

        @Test
	public void demo(){
		UserDao userDao = new UserDaoImpl();
		//创建代理
		UserDao proxy = new JdkProxy(userDao).createProxy();
		proxy.save();
		proxy.delete();
		proxy.find();
		proxy.update();
	}

 

Cglib代理

                  不需要实现接口

public class CustomerDao {
	public void save() {
		System.out.println("保存用户");
	}
	public void update() {
		System.out.println("修改用户");
	}
	public void find() {
		System.out.println("查询用户");
	}
	public void delete() {
		System.out.println("删除用户");
	}
}

                    代理类 

public class CglibProxy implements MethodInterceptor{
	private CustomerDao customerDao;
	
	public CglibProxy(CustomerDao customerDao){
		this.customerDao = customerDao;
	}
	
	/**
	 * 使用cglib产生代理的方法
	 */
	public CustomerDao createProxy(){
		//创建cglib的核心对象
		Enhancer enhancer = new Enhancer();
		//设置父类
		enhancer.setSuperclass(customerDao.getClass());
		//设置回调(类似于InvocationHandler对象)
		enhancer.setCallback(this);
		//创建代理对象
		CustomerDao customerDao = (CustomerDao)enhancer.create();
		return customerDao;
	}
	@Override
	public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		//判断方法是否为save
		if("save".equals(method.getName())){
			//增强
			System.out.println("权限校验=================");
		}
		return methodProxy.invoke(customerDao, args);
	}
}

 

@Test
	public void test(){
		CustomerDao customerDao = new CustomerDao();
		//创建代理
		CustomerDao proxy = new CglibProxy(customerDao).createProxy();
		proxy.save();
		proxy.delete();
		proxy.find();
		proxy.update();
	}

相关术语

public interface ProductDao {
	public void save();
	public void update();
	public void find();
	public String delete();
}

Joinpoint:连接点,可以被拦截的点

这里的CRUD方法都可以被增强,这些方法就可以成为连接点

Pointcut:切入点,真正被拦截的点

比如只对save方法增强,在save执行前进行权限校验,那save方法就是切入点

Advice:通知,增强 方法层面的增强

在save执行前进行权限校验,那么权限校验方法就是通知

Introduction:引介,类层面的增强

Target:被增强的对象

 对ProductDao进行增强,那么ProductDao就是目标

Weaving:织入,将通知应用到目标的过程

 Aspect:切面,多个通知和多个切入点的组合

Proxy:代理对象 

AOPxml开发案例 

 在spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html中找到aop开发的约束

<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" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd"> 
</beans>	

目标为是实现接口的类,底层采用的是jdk代理

public interface ProductDao {
	public void save();
	public void update();
	public void find();
	public String delete();
}

public class ProductDaoImpl implements ProductDao{

	@Override
	public void save() {
		System.out.println("保存商品");
	}

	@Override
	public void update() {
		System.out.println("更改商品");
	}

	@Override
	public void find() {
		System.out.println("查找存商品");
	}

	@Override
	public String delete() {
		System.out.println("删除商品");
		return "测试后置通知的返回值";
	}
}

 配置目标和切面

        <!-- 配置目标对象 -->
	<bean id="ProductDao" class="demo3.ProductDaoImpl"></bean>
	<!-- 将切面类交给Spring管理 -->
	<bean id="MyAspectXML" class="demo3.MyAspectXML"></bean>

通知类型:

 前置通知

后置通知

异常抛出通知

最终通知

环绕通知

 切面类

public class MyAspectXML {

	/**
	 * 前置通知
	 */
	public void checkPri(JoinPoint joinPoint){
		System.out.println("前置通知======================" + joinPoint);
	}
	
	/**
	 * 后置通知
	 * 	这里的result根据配置文件中returning值而来,与returning的值必须一样,
	 *      但returning的值可以随便取
	 */
	public void writeLog(Object result){
		System.out.println("后置通知========================" + result);
	}
	
	/**
	 * 环绕通知
	 * @throws Throwable 
	 */
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
		System.out.println("环绕前通知============");
		Object obj = proceedingJoinPoint.proceed();
		System.out.println("环绕后通后============");
		return obj;
	}
	
	/**
	 * 异常抛出通知
	 */
	public void afterThrowing(Throwable e){
		System.out.println("异常抛出通知" + e.getMessage());
	}
	
	/**
	 * 最终通知---相当于finally代码块中的内容
	 */
	public void after(){
		System.out.println("最终通知");
	}
}

配置切面类

<!-- 通过AOP的配置完成对目标类产生代理 -->
	<aop:config>
		<!-- 表达式配置哪些类的哪些方法需要进行增强 -->
		<aop:pointcut expression="execution(* demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
		<aop:pointcut expression="execution(* demo3.ProductDaoImpl.delete(..))" id="pointcut2"/>
		<aop:pointcut expression="execution(* demo3.ProductDaoImpl.update(..))" id="pointcut3"/>
		<aop:pointcut expression="execution(* demo3.ProductDaoImpl.find(..))" id="pointcut4"/>
		<!-- 配置切面 -->
		<aop:aspect ref="MyAspectXML">
			<!-- 前置通知 -->
			<aop:before method="checkPri" pointcut-ref="pointcut1"/>
			<!-- 后置通知 -->
			<aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
			<!-- 环绕通知 -->
			<aop:around method="around" pointcut-ref="pointcut3" />
			<!-- 异常抛出通知 -->
			<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="e" />
			<!-- 最终通知 -->
			<aop:after method="after" pointcut-ref="pointcut4" />
		</aop:aspect>
	</aop:config>

测试类

 传统的创建工厂的测试方法

	@Test
	public void test(){
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		ProductDao productDao = (ProductDao)applicationContext.getBean(ProductDao.class);
				productDao.save();
				productDao.update();
				productDao.delete();
				productDao.find();
	}

采用单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
	@Resource(name="ProductDao")
	private ProductDao productDao;
	@Test
	public void test(){
		productDao.save();
		productDao.update();
		productDao.delete();
		productDao.find();
	}
	
}

 

AOP注解开发案例

jar包和约束与xml开发一致

这里的目标没有用到接口,底层采用的Cglib代理

public class OrderDao {
	public void save(){
		System.out.println("保存订单");
	}
	public void update(){
		System.out.println("修改订单");
	}
	public void delete(){
		System.out.println("删除订单");
	}
	public void find(){
		System.out.println("查询订单");
		int i = 1 / 0;
	}
}

 需要在xml中开启aop注解开发,需要配置

        <!-- 在配置文件中开启注解的AOP开发(这样就可以在切面类中使用注解) -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

还需要配置目标和切面

        <!-- 配置目标类 -->
	<bean id="OrderDao" class="demo1.OrderDao"></bean>
	<!-- 配置切面类 -->
	<bean id="MyAspectAnno" class="demo1.MyAspectAnno"></bean>

 在类上加上@Aspect注解,说明这个类是切面类

@Aspect
public class MyAspectAnno {

	//前置通知
	@Before(value = "execution(* demo1.OrderDao.save(..))")
	public void before(){
		System.out.println("前置通知================");
	} 
	
	//后置通知---方法参数必须与returning值一样
	@AfterReturning(value = "execution(* demo1.OrderDao.delete(..))",returning="result")
	public void AfterReturning(Object result){
		System.out.println("后置通知================"+result);
	} 
	
	//环绕通知
	@Around(value = "execution(* demo1.OrderDao.update(..))")
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
		System.out.println("环绕前================");
		Object obj = proceedingJoinPoint.proceed();
		System.out.println("环绕后================");
		return obj;
	} 
	
	//异常抛出通知
	@AfterThrowing(value = "execution(* demo1.OrderDao.find(..))",throwing="e")
	public void afterThrowing(Throwable e){
		System.out.println("异常抛出通知================"+e.getMessage());
	} 
	
	//最终通知
	@After(value = "execution(* demo1.OrderDao.find(..))")
	public void after(){
		System.out.println("最终通知================");
	} 
	
	
	
	/**
	 * 简写方式:
	 *        自定义一个方法,比如pointcut1,给这个方法配一个@Pointcut注解,
	 *        注解的value值如果是execution(* demo1.OrderDao.find(..)),
	 *        那么用到execution(* demo1.OrderDao.find(..))的地方就可以用【这个类的类名】.pointcut1()替代
	 */
	@Pointcut(value="execution(* demo1.OrderDao.find(..))")
	private void pointcut1(){}
}

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值