在Spring AOP编程中:
如果加入容器中的目标对象有实现接口,用 JDK代理;
如果目标对象没有实现接口,用 Cglib代理;
手动实现 AOP编程:
AOP面向切面编程: AOP业务代码与关注点代码分离;
关注点: 重复的代码(方法)叫关注点;
切面: 关注点形成的类叫切面类;
AOP: 关注点代码只写一次;
开发者只需要关注核心代码;
运行时,执行核心业务代码,动态植入关注点代码【用代理类】
1. 没有用代理类时,直接在实现类即目标对象中添加代码——》将代码提取出来形成方法——》将重复代码形成的方法提取出来形成类,再在目标类的业务代码前后调用生成的类对象中的关注点代码(所以要想调用关注点代码形成的类中的方法,目标类中就要有相对应的对象属性):目标对象中要用到 MyAop类对象 aop,用注解生成,所以 MyAop.java类添加 @Component注解自动形成对象;再注入进目标对象,所以类中属性 aop前添加@Resource注解将容器中生成的 MyAop 对象aop注入进来;再在业务代码前后调用对象 aop中的方法(中的关注点代码); 测试类中最终要调用目标对象中的方法,要得到目标类的 bean对象 userDao,所以 UserDao.java类上添加@Component(“userDao”)注解在容器中生成 userDao对象。
1.1 IUserDao.java
(接口中有一个 save方法)
public interface IUserDao{
public void save() throws Exception;
}
1.2 UserDao.java(目标对象提取成单独类之前:)
(直接在实现类即目标对象中添加代码——》将重复代码提取出来形成方法——》将重复代码形成的方法提取出来形成类)
public class UserDao implements IUserDao{
public void save() throws Exception{
//System.out.println("开始事务"); //关注点代码(开始事务)
beginTrans(); //业务代码
System.out.println("----数据已保存----"); //关注点代码(提交事务)
commitTrans();
//System.out.println("提交事务"); //提交事务
}
public void beginTrans(){
System.out.println("开始事务");
}
public void commitTrans(){
System.out.println("提交事务");
}
}
1.2 UserDao.java(目标对象提取成单独类之后:)
(UserDao中要用到 aop对象,用注解生成,所以 MyAop.java类添加 @Component注解自动形成对象;再注入进来,所以类中 aop前添加@Resource注解将容器中生成的 MyAop 对象aop注入进来;再在业务代码前后调用对象 aop中的方法;)
@Component("userDao")
public class UserDao implements IUserDao{
@Resource
private MyAop aop;
public void save() throws Exception{
aop.beginTrans();
System.out.println("----数据已保存----");
aop.commitTrans();
}
}
1.3 MyAop.java
(目标对象提取后形成的单独类)
@Component
public class MyAop{
public void beginTrans(){
System.out.println("开始事务");
}
public void commitTrans(){
System.out.println("提交事务");
}
}
1.4 bean.xml
(IOC容器用注解自动生成bean对象之前开启Spring扫描)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- base-package扫描包即子包下的类 -->
<context:component-scan base-package="com.asd.myaop"></context:component-scan>
</beans>
Test.java
(要用到 UserDao的 bean对象userDao,所以 UserDao.java类上添加@Component注解;)
public class Test{
public static void main(String[] args) {
ApplicationContext applicationContext=new ApplicationContext("bean.xml");
IUserDao userDao=(IUserDao)applicationContext.getBean("userDao");
try{
userDao.save();
}catch(Exception e){
e.printStackTrace();
}
}
}
运行结果:
2. 手动实现利用代理工厂实现AOP
(① ProxyFactory.java类中有两个属性:private static Object target; private static MyAop aop;:目标对象、myAop对象,所以在对应的两个类上分别用@Component(“userDao”)注解生成对应的两个 bean对象; ② 在 bean1.xml中利用静态方法生成对应bean对象 userProxy,且将两个属性注入;③ Test.java中得到 userProxy的 bean对象,调用其 save方法;)
2.1 IUserDao.java
public interface IUserDao{
public void save() throws Exception;
}
2.2 UserDao.java(目标对象)
@Component("userDao")
public class UserDao implements IUserDao{
public void save() throws Exception{
System.out.println("----数据已保存----");
}
}
2.3 MyAop.java
(目标对象提取后形成的单独类)
@Component
public class MyAop{
public void beginTrans(){
System.out.println("开始事务");
}
public void commitTrans(){
System.out.println("提交事务");
}
}
2.4 ProxyFactory.java
public class ProxyFactory{
//目标对象
private static Object target;
private static MyAop aop;
//代理对象
public static Object getProxyFactory(Object _target,MyAop _aop){
target _target;
aop _aop;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass.getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
aop.beginTrans();
Object resultValue=method.invoke(target,args);
aop.commitTrans();
return resultValue;
}
}
);
}
}
2.5 bean1.xml
(ProxyFactory类中 getProxyFactory是静态方法,ref 引用 IOC容器中已经生成的 userDao对象(UserDao.java类上@Component(“userDao”)注解生成),)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- base-package扫描包即子包下的类 -->
<context:component-scan base-package="com.asd.myaop1"></context:component-scan>
//ProxyFactory类中 getProxyFactory是静态方法
<bean id="userProxy" class="com.asd.myaop1.ProxyFactory" factory-method="getProxyFactory">
<constructor-arg index="0" ref="userDao"></constructor-arg>
<constructor-arg index="1" ref="myAop"></constructor-arg>
</bean>
</beans>
Test.java
public class Test{
public static void main(String[] args) {
ApplicationContext applicationContext=new ApplicationContext("bean1.xml");
IUserDao proxy=(IUserDao)applicationContext.getBean("userProxy");
try{
proxy.save();
}catch(Exception e){
e.printStackTrace();
}
}
}
运行结果: