面向方面编程(Spring AOP)
分散关注:
将通用需求功能从不相关类中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
AOP就是这种实现分散关注的编程方法,它将”关注”封装在”方面”中
AOP是什么?
AOP 是OOP的延续,是Aspect Oriented Programming 的缩写,意思是面向方面编程。他实际上是Gof设计模式的延续,主要是为了解耦。它是一种编程技术,用来在系统中提升业务分离。AOP将服务模块化,并把它们声明式的应用在需要的地方。从点到点的思维转向点到面的思维,这就是面向切面编程。
优点: AOP以“动态织入”的方式大大提高了应用开发效率,有效的降低软件的复杂性,代码的清晰性、模块化、可测试性方面也会取得很好的提升。
AOP的基本术语:
切面(Aspect):要实现的交叉功能。它是应用系统模块化的一个切面或领域。就是说你附加些撒子功能
连接点(JoinPoint):是应用程序执行过程中插入切面的地点。这个地方可以是方法调用,异常抛出,修改字段。 在Spring中,连接点就特指对某个方法的调用。连接点就无非方法
通知(Advice):通知是指某个切入点要执行的代码。就是你要让你的方法干些什么事
切入点(pointcut):定义通知应该应用在那些连接点。你附加的功能加到那个方法
目标对象(target):目标对象是被通知的对象。 就是你要附加功能的类嘛!
织入(weaving):切面应用到目标对象从而创建一个新的代理对象的过程
Spring 的AOP实现:
第一:创建通知
通知就是包含了切面逻辑的JavaBean
前置通知:(MethodBeforeAdvice)接口。
before(Method method, Object[] args, Object target) 这个方法有三个参数,第一个参数是个Method目标方法的属性。
Object[] args对象数组,它保存了调用目标方法时所传递的参数
Object target 保存目标方法所属的对象。
前置通知没有返回值,唯一能阻止目标方法就是抛出异常
后置通知:(AfterReturningAdvice)接口,afterReturning(Object obj,Method method,Object[] arg1,Object arg2) 这个方法有四个参数
Object obj 保存目标方法的返回结果对象
Method method 目标方法的属性
Object[] arg1 调用目标方法所调用的方法
Object arg2目标方法所属的对象
第二 :定义切入点
Advice 与 Advisor 的区别?
Advice :通知,就是切入点要执行的代码
Adivsor :通知和切入点组合到一个对象
第三:使用ProxyFactoryBean
他主要是用来创建代理对象,那么为什么要创建代理对象啦!
因为我们AOP是用到的,动态代理模式,实现动态代理就必须 代理对象 和 目标对象 他们实现同一个接口,就是吧添加的功能分化出来实现
要我说:理解AOP 就要好好理解下动态代理模式,理解这其中的原理,方法,方法所要传的参数,配置xml文件无非把参数传入,描述他们之间的关系
这其中的属性有:
Target 代理目标对象
ProxyInterface 代理应该实现的接口
InterceptorNames :需要应用到目标对象上的通知Bean名字
自动代理:(BeanNameAutoProxyCreator, DefaultAdvisorAutoProxyCreator)
理论知识完!!!!!!!!!
代码演示部分!
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<beans>
<!-- 目标对象,相当于面包 就是我们的目标对象 target-->
<bean id="bankService" class="com.lovo.BankServiceImpl"></bean>
<!-- 定义通知,相当于牛肉 就是我们的通知Advice-->
<bean id="logAdvice" class="com.lovo.LogAdvice"></bean>
<!-- 定义一个切入点实现,相当于一个面包师,他知道在哪里添加牛肉 Advisor它是把通知和切入点组合到一个对象中-->
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="logAdvice"></property>
<property name="mappedNames">
<list>
<value>zz</value>
<value>save</value>
</list>
</property>
</bean>
<!--
<bean id="logAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="logAdvice"></property>
<property name="pattern" value=".*zz"></property>
</bean>
-->
<!-- 制作汉堡,放入面包,牛肉,返回汉堡,而不是汉堡工厂自己 -->
<bean id="bankProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="bankService"></property>
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
<property name="interfaces">
<list>
<value>com.lovo.BankService</value>
</list>
</property>
</bean>
<!-- 定义学生目标对象 -->
<bean id="student" class="com.lovo.s.StudentServieImpl"></bean>
<bean id="studentProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="student"></property>
<property name="interceptorNames">
<value>logAdvisor</value>
</property>
<property name="interfaces">
<value>com.lovo.s.StudentService</value>
</property>
</bean>
</beans>
自动代理部分:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<beans>
<!-- 目标bean对象 -->
<bean id="bankService" class="com.lovo.BankServiceImpl"></bean>
<bean id="studentService" class="com.lovo.s.StudentServieImpl"></bean>
<!-- 通知,具体切面的实现 -->
<bean id="logAdvice" class="com.lovo.LogAdvice"></bean>
<!-- 一个advisor,定义了切入点,也就是在那些链接点上应用通知 -->
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="logAdvice"></property>
<property name="mappedNames">
<list>
<value>zz</value>
<value>save</value>
</list>
</property>
</bean>
<!-- 定义自动代理,spring会自动寻找符合条件的bean,然后封装为代理对象返回,
使用getBean("xxxService"); 返回的就是一个代理对象。
-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
</beans>
回调?
回调在hibernate 与 spring结合中,用到的非常多。
列举一个简单的回调实例:
AhibernateCallback 接口:
public interface AHibernateCallback {
public Object doInHibernate(Session session);
}
AhibernateTemplate 类: 这里用到了 模板模式,简单理解就是把不变的与可变的分离。 即所谓的开、闭原则
public class AHibernateTemplate {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Object query(AHibernateCallback action){
Session session = this.sessionFactory.openSession();
Object obj = action.doInHibernate(session);
session.close();
return obj;
}
}
UserDao 类:
ublic class UserDao {
private AHibernateTemplate template;
public void setTemplate(AHibernateTemplate template) {
this.template = template;
}
public Object getUser(final int id){
return this.template.query(new AHibernateCallback(){
public Object doInHibernate(Session session) {
String hql = "from User u where u.id = ?";
return session.createQuery(hql).setParameter(0, id).uniqueResult();
}});
}
Test类:
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("s6.xml");
UserDao dao = (UserDao) ctx.getBean("userDao");
User u = (User) dao.getUser(2);
System.out.println(u.getUserName());
}
}
JAVA的CALLBACK通过接口来实现。
例:
1.class A,class B
2.class A实现接口operate
3.class B拥有一个参数为operate接口类型的函数test(operate o)
4.class A运行时调用class B中test函数,以自身传入参数
5.class B已取得A,就可以随时回调A所实现的operate接口中的方法
分散关注:
将通用需求功能从不相关类中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
AOP就是这种实现分散关注的编程方法,它将”关注”封装在”方面”中
AOP是什么?
AOP 是OOP的延续,是Aspect Oriented Programming 的缩写,意思是面向方面编程。他实际上是Gof设计模式的延续,主要是为了解耦。它是一种编程技术,用来在系统中提升业务分离。AOP将服务模块化,并把它们声明式的应用在需要的地方。从点到点的思维转向点到面的思维,这就是面向切面编程。
优点: AOP以“动态织入”的方式大大提高了应用开发效率,有效的降低软件的复杂性,代码的清晰性、模块化、可测试性方面也会取得很好的提升。
AOP的基本术语:
切面(Aspect):要实现的交叉功能。它是应用系统模块化的一个切面或领域。就是说你附加些撒子功能
连接点(JoinPoint):是应用程序执行过程中插入切面的地点。这个地方可以是方法调用,异常抛出,修改字段。 在Spring中,连接点就特指对某个方法的调用。连接点就无非方法
通知(Advice):通知是指某个切入点要执行的代码。就是你要让你的方法干些什么事
切入点(pointcut):定义通知应该应用在那些连接点。你附加的功能加到那个方法
目标对象(target):目标对象是被通知的对象。 就是你要附加功能的类嘛!
织入(weaving):切面应用到目标对象从而创建一个新的代理对象的过程
Spring 的AOP实现:
第一:创建通知
通知就是包含了切面逻辑的JavaBean
前置通知:(MethodBeforeAdvice)接口。
before(Method method, Object[] args, Object target) 这个方法有三个参数,第一个参数是个Method目标方法的属性。
Object[] args对象数组,它保存了调用目标方法时所传递的参数
Object target 保存目标方法所属的对象。
前置通知没有返回值,唯一能阻止目标方法就是抛出异常
后置通知:(AfterReturningAdvice)接口,afterReturning(Object obj,Method method,Object[] arg1,Object arg2) 这个方法有四个参数
Object obj 保存目标方法的返回结果对象
Method method 目标方法的属性
Object[] arg1 调用目标方法所调用的方法
Object arg2目标方法所属的对象
第二 :定义切入点
Advice 与 Advisor 的区别?
Advice :通知,就是切入点要执行的代码
Adivsor :通知和切入点组合到一个对象
第三:使用ProxyFactoryBean
他主要是用来创建代理对象,那么为什么要创建代理对象啦!
因为我们AOP是用到的,动态代理模式,实现动态代理就必须 代理对象 和 目标对象 他们实现同一个接口,就是吧添加的功能分化出来实现
要我说:理解AOP 就要好好理解下动态代理模式,理解这其中的原理,方法,方法所要传的参数,配置xml文件无非把参数传入,描述他们之间的关系
这其中的属性有:
Target 代理目标对象
ProxyInterface 代理应该实现的接口
InterceptorNames :需要应用到目标对象上的通知Bean名字
自动代理:(BeanNameAutoProxyCreator, DefaultAdvisorAutoProxyCreator)
理论知识完!!!!!!!!!
代码演示部分!
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<beans>
<!-- 目标对象,相当于面包 就是我们的目标对象 target-->
<bean id="bankService" class="com.lovo.BankServiceImpl"></bean>
<!-- 定义通知,相当于牛肉 就是我们的通知Advice-->
<bean id="logAdvice" class="com.lovo.LogAdvice"></bean>
<!-- 定义一个切入点实现,相当于一个面包师,他知道在哪里添加牛肉 Advisor它是把通知和切入点组合到一个对象中-->
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="logAdvice"></property>
<property name="mappedNames">
<list>
<value>zz</value>
<value>save</value>
</list>
</property>
</bean>
<!--
<bean id="logAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="logAdvice"></property>
<property name="pattern" value=".*zz"></property>
</bean>
-->
<!-- 制作汉堡,放入面包,牛肉,返回汉堡,而不是汉堡工厂自己 -->
<bean id="bankProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="bankService"></property>
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
<property name="interfaces">
<list>
<value>com.lovo.BankService</value>
</list>
</property>
</bean>
<!-- 定义学生目标对象 -->
<bean id="student" class="com.lovo.s.StudentServieImpl"></bean>
<bean id="studentProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="student"></property>
<property name="interceptorNames">
<value>logAdvisor</value>
</property>
<property name="interfaces">
<value>com.lovo.s.StudentService</value>
</property>
</bean>
</beans>
自动代理部分:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<beans>
<!-- 目标bean对象 -->
<bean id="bankService" class="com.lovo.BankServiceImpl"></bean>
<bean id="studentService" class="com.lovo.s.StudentServieImpl"></bean>
<!-- 通知,具体切面的实现 -->
<bean id="logAdvice" class="com.lovo.LogAdvice"></bean>
<!-- 一个advisor,定义了切入点,也就是在那些链接点上应用通知 -->
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="logAdvice"></property>
<property name="mappedNames">
<list>
<value>zz</value>
<value>save</value>
</list>
</property>
</bean>
<!-- 定义自动代理,spring会自动寻找符合条件的bean,然后封装为代理对象返回,
使用getBean("xxxService"); 返回的就是一个代理对象。
-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
</beans>
回调?
回调在hibernate 与 spring结合中,用到的非常多。
列举一个简单的回调实例:
AhibernateCallback 接口:
public interface AHibernateCallback {
public Object doInHibernate(Session session);
}
AhibernateTemplate 类: 这里用到了 模板模式,简单理解就是把不变的与可变的分离。 即所谓的开、闭原则
public class AHibernateTemplate {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Object query(AHibernateCallback action){
Session session = this.sessionFactory.openSession();
Object obj = action.doInHibernate(session);
session.close();
return obj;
}
}
UserDao 类:
ublic class UserDao {
private AHibernateTemplate template;
public void setTemplate(AHibernateTemplate template) {
this.template = template;
}
public Object getUser(final int id){
return this.template.query(new AHibernateCallback(){
public Object doInHibernate(Session session) {
String hql = "from User u where u.id = ?";
return session.createQuery(hql).setParameter(0, id).uniqueResult();
}});
}
Test类:
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("s6.xml");
UserDao dao = (UserDao) ctx.getBean("userDao");
User u = (User) dao.getUser(2);
System.out.println(u.getUserName());
}
}
JAVA的CALLBACK通过接口来实现。
例:
1.class A,class B
2.class A实现接口operate
3.class B拥有一个参数为operate接口类型的函数test(operate o)
4.class A运行时调用class B中test函数,以自身传入参数
5.class B已取得A,就可以随时回调A所实现的operate接口中的方法