1.servlet的AOP体现:
AOP意思就是面向切面编程,可以用一句话概况AOP编程思想,即横向重复,纵向抽取。我们知道,软件工程一个基本原则就是代码复用,为了实现这个目标,我们可以用类,用方法,同样,AOP也是代码复用的一种方式。我们现在用下面这样一种例子来具体解释什么叫做面向切面编程。熟悉 java web的朋友可能清楚,我们在编写servlet需要解决一系列的乱码问题,此时可以用filter一次性解决servlet乱码问题。此处的servlet中的乱码问题就是横向重复,而filter就是纵向抽取。可用下图表示此个例子。
2.SSH框架中的AOP思想体现
在SSH框架中,一个典型的例子就是service层中的事务管理,没一个service层都需要实现事务管理的代码,这就是所谓横向重复,spring能够为容器中的对象生成动态代理对象(spring中使用动态代理技术实现AOP),通过这个代理对象能够纵向管理事务操作。
具体如图解释。
基本原理:通过生成代理对象,对原来的方法进行增强。根据生成对象的方式不同,分为两类。一类为动态代理,要求被代理的对象必须实现接口。一类为cglib代理,可以对任何类实现代理,原理为继承代理,若类被final修饰,则无法代理。
方式一解析:动态代理方式实现一个类中的方法
现在假设dao层有一个类UserDao,这个类有一个方法Save用来保存用户数据,一般在保存数据前,我们需要进行权限判断,而这个权限判断是为横向的重复操作,所以可以用AOP思想把它纵向抽取,然后通过动态代理技术把save方法增强,使其在进行保存之前进行权限判断。下面是动态代理的代码实现。
public class MyJDKProxy implements InvocationHandler//动态代理必须实现此接口
{
private UserDao userDao;
public MyJDKProxy(UserDao userDao) {
this. userDao = userDao;
}
//通过java中的代理类Proxy,生成UserDao的代理对象:
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
{
if("save".equals(method.getName())){
System. out.println("权限判断================");
}
return method.invoke(userDao, args);
}
}
方式二解析:Cglib动态代理技术生成一个代理对象。
Cglib是第三方的代理技术,被spring集成使用,原理是对目标对象进行继承代理,底层是字节码增强技术,生成当前类的子类对象。现在为上面的情况为save方法加入权限判断代码。Cglib动态代理对象的方式如下
public class MyCglibProxy implements MethodInterceptor{
private CustomerDao customerDao;
public MyCglibProxy(CustomerDao customerDao){
this. customerDao = customerDao;//获得需要增强方法的目标类
}
// 生成代理的方法:
public CustomerDao createProxy(){
// 创建 Cglib 的核心类:
Enhancer enhancer = new Enhancer();
// 设置父类:
enhancer.setSuperclass(CustomerDao. class);
// 设置回调:
enhancer.setCallback(this);
// 生成代理:
CustomerDao customerDaoProxy = (CustomerDao) enhancer.create();
return customerDaoProxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
methodProxy) throws Throwable {
if("save".equals(method.getName())){
Object obj = methodProxy.invokeSuper(proxy, args);
System. out.println("权限判断================");
return obj ;
}
return methodProxy.invokeSuper(proxy, args);
}
}
1.spring中AOP开发中的相关术语
Joinpoint(连接点): 目标对象中,所有可以增强的方
Pointcut(切入点): 目标对象所有已经增强的方法
Advice(通知/增强): 增强的代码
前置通知 :在目标方法执行之前执行.
后置通知 :在目标方法执行之后执行
环绕通知 :在目标方法执行前和执行后执行
异常抛出通知:在目标方法执行出现 异常的时候 执行
最终通知 :无论目标方法是否出现异常 最终通知都会 执行.
Target(目标对象): 代理的目标对象
Weaving(织入): 将通知应用到切入点的过程,spring 采用动态代理织入
Proxy(代理) : 将通知织入到目标对象后,形成代理对象。
Aspect(切面):切入点+通知
2.spring使用XML进行AOP的开发
spring内部已经实现了动态代理,在实际开发时,只需要准备后通知,然后在主配置文件中把通知配置到需要增强的方法中即可。
步骤一,导入AOP开发中所需要的jar包(四个)
1. spring-aspects-4.2.4.RELEASE.jar
2. spring-aop-4.2.4.RELEASE.jar
3. com.springsource.org.aopalliance-1.0.0.jar
4. com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
步骤二,准备好目标对象
创建接口和类:
public interface UserService {
public void save();
public void update();
public void delete();
public void find();
}
public class UserServiceImpl implements UserService{
@Override
public void save() {
System. out.println("保存用户...");
}
@Override
public void update() {
System. out.println("修改用户...");
}
@Override
public void delete() {
System. out.println("删除用户...");
}
@Override
public void find() {
System. out.println("查询用户...");
}
}
步骤三,准备通知
public class Myadvice{
public void before()
{
System.out.println("前置增强")
}
public void afterReturning()
{
System.out.println("后置增强,出现异常不会调用")
}
public Object around(ProceedingJoinPoint pjp)throw Throwable{
System. out.println("环绕通知前的通知===========");
Object proceed=pjp.proceed();//调用目标方法
System. out.println("环绕通知后的通知===========");
return proceed;
}
public void afterException(){
System. out.println("出现异常调用===========");
}
public void after(){
System. out.println("后置增强,出现异常依然调用===========");
}
}
步骤四.配置讲通知织入目标对象中
目标类的配置:
切面类的配置:
AOP的配置:
...其他几种通知配置如以上两种类似
至此,完成spring中AOP的XML全部配置
3.spring使用注解方式配置AOP
前四步与XML配置方式完全一致:导包–准备目标对象–准备通知–把目标对象和通知对象配置到主配置文件
区别在于:此种方式在在编写通知方法时用注解方式进行配置。以前置通知与后置通知为例。
@Aspect
//表明该类是一个通知类
public class MyAdvice {
//引入目标对象,这句话意思是方法切入点,execution为执行的意思,*代表任意返回值,然后是包名,
.*意思是包下面的所有子包。(..)代表各种方法.
@Pointcut("execution(*com.cai.service.ServiceImpl.*(...))")
public void pointcut1{}
// 前置增强
@Before("Myadvice.pointcut1()")
public void before(){
System. out.println("前置增强===========");
}
@AfterReturning("Myadvice.pointcut1()")
public void afterReturning(){
System. out.println("后置通知,出现异常不会调用===========");
}
…其他几种类型的通知类似配置
四.总结
AOP思想是spring中至关重要的编程思想,也是spring如此强大的原因之一,使用AOP思想,可以完成如事务控制,日志记录,权限校验一一系列工作,方便开发进行。