引言:AOP全称为Aspect Oriented Programming即为面向面变成,它是一种变成思想;Spring为了管理日志信息,事务信息以及异常等信息将这种思想加入到了自己的架构中;我们称之为SpringAOP;
一:究竟什么是面向切面编程?
百度百科:通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续;是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
引用知乎上一人回答:就是在程序执行过程中动态地将代码切入到类的指定方法或者指定位置上的编程思想;
二:怎么使用?
在java的Spring框架中具体有两种实现方法,一种是通过JDK的动态代理实现,一种是通过Cglib的动态代理实现;
1:早期的Aop:
A:通过JDK的动态代理实现:
a:需要接口b:实现类(代理类)c:织入类d:代理类
//接口类
package com.cp.insist.dao;
import com.cp.insist.entity.User;
public interface InteUserDao {
public void updateUser(Integer id ,User user);
}
//实现类
public class userDao implements InteUserDao{
@Override
public void updateUser(Integer id,User user) {
System.out.println("更新用户的id为:"+id+"用户为"+user);
}
}
package com.cp.insist.dao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* java动态代理类必须要有一个接口
这是一个织入类
* @author 陈鹏
*
*/
public class UserHander implements InvocationHandler{
private Object target;
/**
*
* @Description:通过构造方法去传递目标对象
* @创建时间 2016年7月18日
* @创建人 陈鹏
* @throws
*/
public UserHander(Object source){
this.target=source;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("开始提交事务了。。。");
// 执行代理的方法
Object object = method.invoke(target, args);
System.out.println("提交事务成功了!!!");
return object;
}
}
/测试类
package com.cp.insist.test;
import java.lang.reflect.Proxy;
import com.cp.insist.dao.InteUserDao;
import com.cp.insist.dao.UserHander;
import com.cp.insist.dao.userDao;
public class MainTest {
public static void main(String[] args) {
1:闯将一个实现类,被代理的对象
IUserDao userDao = new UserDaoImpl();
2:动态处理对象
UserHandler userHandler = new UserHandler(userDao);
3:创建一个代理对象
IUserDao proxy = (IUserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
userHandler);
proxy.saveUser(new User());
}
}
使用cglib来进行Aop的动态代理的处理,简化了jdk的Aop动态代理的处理
不需要使用接口;
代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
1:建一个dao类,再建一个动态的处理类实现MethodInterceptor类;
2:并且重写里面的方法,再调用ivoinvokeSuper方法
//被代理类
public class userDao {
public void saveUser(User user){
System.out.println("进入了user的保存方法");
}
}
//织入类
public class userProxy implements MethodInterceptor{
//增强对象
private Enhancer enhancer = new Enhancer();
public Object getProxyObject(Class clz){
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] arrO,
MethodProxy proxy) throws Throwable {
System.out.println("这里提交事务!!");
//调用方法
Object obj = proxy.invokeSuper(arg0, arrO);
System.out.println("主要业务");
return obj;
}
}
测试类:
public class Test {
public static void main(String[] args) {
userProxy proxy = new userProxy();
userDao user = (userDao)proxy.getProxyObject(userDao.class);
user.saveUser(new User());
}
}
2:引入注解之后的Aop
同样也分jdk的动态代理和cglib的动态代理
这里我们只将jdk的动态代理
//接口
public interface Iuser {
public void say(String name) throws SQLException;
}
//实现类
public class UserImp implements Iuser{
@Override
public void say(String name) throws SQLException {
System.out.println("我是一个"+name+"通知"+"目的方法");
throw new SQLException("对不起查询失败");
}
}
//通知类:这是一个后置通知
public class adviceAfter implements AfterReturningAdvice{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("我是一个后置通知");
}
}
//配置文件:因为我们采用的注解方式:利用IOC思想;让容器去替我们管理对象,所以在相应的配置文件我们需要:
<property name="optimize" value="false"></property>通过设置它的值我们可以选择使用jdk的动态代理还是cglib的动态代理;默认为false,采用jdk的动态代理
<!--通知类-->
<bean id="advice2" class="com.chenpeng.dao2.MethodInterceptorAdvice"></bean>
<!--实现类-->
<bean id ="userimp" class="com.chenpeng.dao2.UserImp"></bean>
<!--根据通知类和实现类去获取代理对像-->
<bean id="factory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userimp"></property>
<property name="interfaces" value="com.chenpeng.dao2.Iuser"></property>
<!-- 第一种方法:多个通知时 -->
<!-- <property name="interceptorNames" value="advice,advice1,advice2,exception"></property> -->
<!-- 第二种方法:多个通知时 -->
<!-- <property name="interceptorNames">
<list>
<value>advice</value>
<value>advice1</value>
<value>advice2</value>
<value>exception</value>
</list>
</property> -->
<!-- 第三种方法:多个通知时 -->
<property name="interceptorNames">
<list>
<idref bean="advice"/>
<idref bean="advice1"></idref>
<idref bean="advice2"></idref>
<idref bean="exception"></idref>
</list>
</property>
</bean>
//测试类
public class test2 {
public static void main(String[] args) {
ApplicationContext content = new ClassPathXmlApplicationContext("classpath:com/chenpeng/dao2/bean.xml");
//jdk动态代理使用接口转型;cjlib的动态代理使用具体类转型
Iuser user = (com.chenpeng.dao2.Iuser)content.getBean("factory");
user.say("前置");
}
}
3:最新的AOP使用Aspectj将切面和植入类进行完美结合省去很多代码
接口类
public interface Iuser {
public void addUser();
public void addUser1();
public void updateUser();
public void updateUser(int a);
}
实现类:
@Component
public class cpUserImp implements Iuser{
@Override
public void addUser() {
System.out.println("我是一个addUser的方法");
}
@Override
public void updateUser() {
System.out.println("我是一个updateUser的方法");
}
@Override
public void addUser1() {
// TODO Auto-generated method stub
System.out.println("我是一个addUser1的方法");
}
@Override
public void updateUser(int a) {
// TODO Auto-generated method stub
System.out.println("我是一个带参数的update方法");
}
}
织入类+切面
@Component
@Aspect
public class aspectAdvitor {
@Before("execution(* add*(..))")//拦截指定的方法
public void say(){
System.out.println("我是一个aspectj版本的aop的方法");
}
@AfterReturning("execution(* update*(..))&&args(int,..)")
public void work(){
System.out.println("我是一个update的work后置通知方法");
}
//环绕型通知
@Around("execution(* update*(..))")
public void round(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("事务开始");
joinPoint.proceed();
System.out.println("事务提交");
}
}
关于配置文件:由于我们采用了注解
第一种方式:
<!-- 表示开启了Aspect模式的Aop -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"></bean>
<!--切面+织入类-->
<bean class="com.chenpeng.dao4.AspectAop"></bean>
<!--具体类-->
<bean id="user" class="com.chenpeng.dao4.UserImp"></bean>
第二种方式:
<!--扫包:将所有添加注解的类相关对象都进行实例化-->
<context:component-scan base-package="com.chenpeng.dao4.**"></context:component-scan>
<!-- 表示开启了Aspect模式的Aop -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
第四种方式:主体的类文件和第三种一样,我们可以将具体的切入点在配置文件书写;更加方便:
<context:component-scan base-package="com.chenpeng.dao6"></context:component-scan>
<aop:config>
<!-- 可以将切点单独定义出来 -->
<aop:pointcut expression="execution(* update*(..))" id="roundAdvisor"/>
<!---ref="aspectAdvitor"-这个就是我们定义的切面和通知类由于扫包了,默认的bean的id就是类名首字母小写->
<aop:aspect ref="aspectAdvitor">
<!--切面类以及执行的方法-->
<aop:after method="say" pointcut="execution(* add*(..))"/>
<!-- 引用上面定义的切点 -->
<aop:around method="round" pointcut-ref="roundAdvisor"/>
</aop:aspect>
</aop:config>
以上就是自己学习spring中的AOP的相关笔记;如果有不对的地方还望大家及时指点;
网友评论