①、通过xml方式配置bean
②、通过annotation(注解)方式配置bean
步骤:
①、在Spring的配置文件中配置自动扫描的包,告知IoC引擎去指定包以及子包下所有资源的注解
②、在相关bean中通过如下注解完成bean的创建以及属性的注入
@Value(“value”):为属性注入具体的值,可以放在变量上面,也可以放在setter风格的方法上面
@Component:创建对象,并纳入到IoC容器管理中。配置限定名为对象名的类纳入到IoC容器中(创建bean对象)
@Autowired:基于类型自动注入引用类型属性
@Repository:创建对象,并纳入到IoC容器管理中。限定名作为对象名 用于定义dao层的组件(IUserDao)
@Service:创建对象,并纳入到IoC容器管理中,限定名作为对象名 用于定义service组件(IUserSerivce)
@Controller:创建对象,并纳入到IoC容器管理中,限定名作为对象名 用于定义业务控制器(Serlvet)
@Scope(“prototype”):设置指定这个IoC对象的作用域 prototype|singleton
@Qualifier(“impl2”):将IoC容器中的impl2这个对象注入给当前对象属性
还记得代理模式中的安全性检查以及日志处理的问题吗?在某写操作执行之前需要做一些安全性检查,比如在删除信息之前需要确定当前账号是否登录过,甚至是哪怕登录过是否具有删除信息的权限呢?还有完成具体操作之后是否需要保存日志信息或者是完成一些资源释放等收尾工作。按照正常实现这些功能,可能会将安全性检查以及日志处理的代码充斥在业务逻辑中,这样并不好,所以Spring针对此类问题提供了AOP技术,对于业务方法来讲只需关注业务实现,而根本不需要关注安全、日志等非业务功能的实现
①、切面 aspect @Aspect
RockSecurity|RockLogger,保存横切关注点方法的代码所在的类叫切面类
②、关注点Pointcut 关注掉表达式
是约定了那些方法切入通知 切入checkSecurity()|saveLogger()
③、通知 advice 即横切关注点表达式的方法
是横切关注点方法的代码所在的方法叫通知
④、连接点JoinPoint
连接点对象可以获取业务方法的相关参数,比如哪个方法?参数列表了等
①、前置通知 @Before
②、后置通知 @After
③、返回(返回值)通知 @AfterReturnning
④、异常通知 @AfterThrowing
⑤、环绕通知 @Around
①、定义切面
package com.rock.springaop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * FileName :com.rock.springaop RockSecurity.java * TODO : * Copyright :Copyright (c) 2015-2016 All Rights Reserved. Company: 01skill-soft.com Inc. * @author :老张 * @Date :2018年11月9日:下午1:29:29 * @version :1.0 * * Modification History: Date Author Version Description * ---------------------------------------------------------------------- * 2018年11月9日 老张 1.0 1.0 Version */ @Aspect @Component public class RockSecurity { /** * @TODO :是一个通知 * @Date :2018年11月9日 下午1:33:01 * @Author :老张 : */ @Before("execution (public int com.rock.springaop.MyMath.add(int,int))") public void checkSecurity(){ System.out.println("RockSecurity.checkSecurity() is running........Before前置通知"); } }
②、定义通知
public void checkSecurity(){ System.out.println("RockSecurity.checkSecurity() is running........Before前置通知"); }
③、定义关注点,约束哪些方法织入通知advice
@Before("execution (public int com.rock.springaop.MyMath.add(int,int))")
IMath.java
package com.rock.springaop;
/**FileName: com.rock.aop IArithmeticCalculate.java
* TODO:
* Copyright: Copyright (c) 2015-2016 All Rights Reserved. Company: 01skill-soft.com Inc.
* @author: 老张
* @Date: 2018年11月9日:上午9:54:42
* @version: 1.0
*
* Modification History: Date Author Version Description
* ----------------------------------------------------------------------
* 2018年11月9日 老张 1.0 1.0 Version
*
*/
public interface IArithmeticCalculate {
/**
* @TODO :实现a+b的和
* @Date :2018年11月9日 上午9:55:05
* @Author :老张
* @param a
* @param b
* @return :和值结果
*/
public int add(int a,int b);
/**
* @TODO :计算a-b
* @Date :2018年11月9日 上午9:56:07
* @Author :老张
* @param a
* @param b
* @return :a-b的结果
*/
public int sub(int a,int b);
/**
* @TODO :a除以b
* @Date :2018年11月9日 上午9:56:34
* @Author :老张
* @param a
* @param b
* @return :a除以b的结果
*/
public int div(int a,int b);
/**
* @TODO :a乘以b
* @Date :2018年11月9日 上午9:57:31
* @Author :老张
* @param a
* @param b
* @return :a乘以b的结果
*/
public int mul(int a,int b);
}
MyMath.java
import org.springframework.stereotype.Component;
/**FileName: com.rock.aop MathProxy.java
* TODO:
* Copyright: Copyright (c) 2015-2016 All Rights Reserved. Company: 01skill-soft.com Inc.
* @author: 老张
* @Date: 2018年11月9日:上午9:54:26
* @version: 1.0
*
* Modification History: Date Author Version Description
* ----------------------------------------------------------------------
* 2018年11月9日 老张 1.0 1.0 Version
*
*/
@Component(value="mymath")
public class IArithmeticCalculateImpl implements IArithmeticCalculate{
@Override
public int add(int a, int b) {
// RockSecurity.检查();
int c=a+b;
// RockLogger.日志保存();
return c;
}
@Override
public int sub(int a, int b) {
// RockSecurity.检查();
int c=a-b;
// RockLogger.日志保存();
return c;
}
@Override
public int div(int a, int b) {
// RockSecurity.检查();
int c=a/b;
// RockLogger.日志保存();
return c;
}
@Override
public int mul(int a, int b) {
// RockSecurity.检查();
int c=a*b;
// RockLogger.日志保存();
return c;
}
}
spring-aop.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<context:component-scan base-package="com.rock.springaop">context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>
①、前置通知
@Aspect @Component public class RockSecurity { /** * @TODO :是一个通知 * @Date :2018年11月9日 下午1:33:01 * @Author :老张 : */ @Before("execution (public int com.rock.springaop.MyMath.add(int,int))") public void checkSecurity(){ System.out.println("RockSecurity.checkSecurity() is running........Before前置通知"); } }
②、后置通知@AfterReturning
/** * @TODO :周知通知,不管被织入方法是否抛出异常,都会执行通知 * @Date :2018年11月9日 下午4:22:53 * @Author :老张 : */ @After("execution (public int com.rock.springaop.MyMath.add(int,int))") public void saveLogger(){ System.out.println("RockLogger.saveLogger() is running........After 后置通知"); }
③、返回(返回值)通知
/** * @TODO :@AfterReturning :返回(返回值)通知 * @AfterReturning,注解中通过指定returning属性告知AOP将被织入的方法的返回值存于哪个变量 * 换言之,若你希望切面能够获取被织入的方法的返回值,必须使用返回通知 * 注意:前置通知和后置通知是获取不了方法的返回值的,它们只能获取到方法的方法名以及参数信息 * @Date :2018年11月9日 下午4:06:11 * @Author :老张 * @param result : */ @AfterReturning(value="execution(* *.*(..))",returning="result") public void returnAdvice(Object result){ System.out.println("RockOther.returnAdvice() is running.........."+result); }
④、异常通知@AfterThrowing
/** * @TODO :@AfterThrowing定义异常通知 * @Date :2018年11月9日 下午4:21:16 * @Author :老张 * @param ex1 : */ @AfterThrowing(value="execution (public int com.rock.springaop.MyMath.*(int,int))",throwing="ex1") public void textException(NullPointerException ex1){ System.out.println("RockLogger.textException() is running........textException 后置通知======="); System.out.println(ex1); }
⑤、环绕通知
/** * @TODO :环绕通知 通过@Around 。环绕通知是功能最为强大的通知 * @Date :2018年11月9日 下午4:27:36 * @Author :老张 * @param jp : */ @Around(value="execution (public int com.rock.springaop.MyMath.*(int,int))") public void textAround(JoinPoint jp){ System.out.println("RockLogger.textAround() is running........"); System.out.println("RockLogger.textAround()"+Arrays.asList(jp.getArgs())); }
5、一般问题总结
//1、切入点表达式的重用
//定义:在切面类中定义一个普通方法,在方法上方通过@Pointcut注解去约定这个方法是一个切入点方法。
//运用:在通知(方法)上方通过全类名.切入点方法名()方式访问
//注意:定义切入点方法的切面应该最先被处理,所以在这个切面中通过@Order(1)注解当前切面的优先级别最高
//2、在advice中怎样获取目标方法的相关数据(参数)
//使用:通过在通知(advice)方法中定义JoinPoint(连接点)获取对应的数据
//注意:别导错包了
//3、在advice方法中要获取目标方法的返回值需要通过返回值通知实现
//使用:@AfterReturning(value="",returning=“abcd”) returning:约定接收目标方法返回值的变量名
//public void testAfterReturnning(Object abcd)
//4、切入点表达式的写法 * …
/*
execution(* .(…))
execution(* com.rock.dao.UserDao.(…))
execution( com.rock.dao..(…))
execution(* com.rock.dao.UserDao.set*(…)) //setUserid setPassword
*/