补充几个其他的写法:

     @Controller         控制器类上

     @Service             业务类上   也可以用@Component

     @Repository        dao类上    也可以用@Component

     @Component       无法归类用

 

          <!-- spring4开始,推荐写法

      p:   property

      p:userDao    userDao->name="userDao"    setUserDao

      p:userDao-ref=userDao   ref引用spring容器中的一个对象userDao

      p:address=""      address->name="address"   value=""

    -->

<bean id="userService1"

      class="com.tarena.service.impl.UserServiceImpl"

        p:userDao-ref="userDao"

        p:address="亦庄"

        p:age="20"></bean>

 

需求:在不更改源代码的前提下,我要填入新功能

          满足了开闭原则,满足单一职责

解决需求:代理设计模式能解决

代理设计模式的分类:

   静态代理

    动态代理

           jdk动态代理

          cglib动态代理

   spring aop (aop 面向切面的编程),spring aop底层还是用的是动态代理

   spring把动态代理封装很好,用户用起来很方便

 

结论:横切性编程,有spring框架支持就用spring aop

                          没有spring框架支持,就用动态代理

做代理的步骤:

   1.必须有业务模型 比如:UserServiceImpl,ProductServiceImpl等

   2.必须新的功能,是要往业务上填入的 比如:事务操作,日志操作,权限等

   3.必须代理类或代理对象,把业务模型和新功能结合(横切,织入)

     

业务模型:

package com.tarena.dao.impl;
 
import com.tarena.dao.UserDao;
 
public class UserDaoImpl implements UserDao {
 
@Override
public int addUser() {
System.out.println("UserDaoImpl.addUser()");
return 1;
}
 
@Override
public int updateUser() {
System.out.println("UserDaoImpl.updateUser()");
return 1;
}
 
}
package com.tarena.service.impl;
 
import com.tarena.dao.UserDao;
import com.tarena.dao.impl.UserDaoImpl;
 
import com.tarena.service.UserService;
 
public class UserServiceImpl implements UserService {
private UserDao userDao=new UserDaoImpl();
 
@Override
public boolean addUser() {
System.out.println("UserServiceImpl.addUser()");
boolean flag=false;
int rowAffect=userDao.addUser();
if(rowAffect==1) {
flag=true;
}
 
return flag;
}
 
@Override
public boolean updateUser() {
System.out.println("UserServiceImpl.updateUser()");
boolean flag=false;
int rowAffect=userDao.updateUser();
if(rowAffect==1) {
flag=true;
}
return flag;
}
 
}

 

 

额外的新功能:

package com.tarena.other;
 
public class TransactionManager {
public void begin() {
    System.out.println("begin transaction");
}
 
public void commit() {
    System.out.println("commit transaction");
}
 
public void rollback() {
    System.out.println("rollback transaction");
}
}

 

 

 

静态代理:静态,说明代理的类和代理的对象,在编译期间就存在,是在运行之前确定静态类和静态对象

静态织入:在编译期间确定耦合关系

package com.tarena.proxy;

 

import com.tarena.other.TransactionManager;

import com.tarena.service.UserService;

/**

 * 本类是一个静态代理类,职责是把业务和新功能结合在一起 ,尽量降低耦合

 * 实现接口是耦合,抽象耦合,耦合的目的,约束此代理类的功能

 * private TransactionManager tm;具体耦合,用组合方式

 * private UserService userService;抽象耦合,用组合方式  完成具体业务功能

 */

public class StaticProxy implements UserService {

    private TransactionManager tm;

    private UserService userService;
    
    public StaticProxy(TransactionManager tm,UserService userService) {

        this.tm=tm;

        this.userService=userService;

}

@Override

public boolean addUser() {

    boolean flag=false;

try {

    tm.begin();

    userService.addUser();

    tm.commit();

    flag=true;

}catch(Exception e) {

    e.printStackTrace();

    tm.rollback();

}

return flag;

}

 

@Override

public boolean updateUser() {

boolean flag=false;

try {

    tm.begin();

    userService.updateUser();

    tm.commit();

    flag=true;

}catch(Exception e) {

    e.printStackTrace();

    tm.rollback();

}

return flag;

}

}

测试方法:

           @Test

public void testMethd2() {

//带事务管理

    TransactionManager tm=new TransactionManager();

    UserService userService=new UserServiceImpl();

    StaticProxy sp=new StaticProxy(tm,userService);

    sp.addUser();

    sp.updateUser();

}

 

 

总结静态代理:

      在编译期就已经写好了代理类,在编译期间确定了耦合关系

      实际的业务跟新的功能解耦(UserServiceImpl和TransactionManager解耦)

     用另一种方式静态代理的方式把(UserServiceImpl和TransactionManager耦合)

          是新添加的类,没用动原业务代码,(从一个代码的泥潭,又进入另一个代码泥潭)

每个具体业务,都要有一个静态代理类

        UserServiceImpl    --->     StaticProxy implements UserService

        ProductServiceImpl --->StaticProxy1 implements ProductService

 

动态代理:

    分类:jdk动态代理,cglib动态代理

     动态代理,是在运行期间来确定代理对象
                        在运行期间确定实际业务和额外的新功能之间的关系

jdk动态代理:

要求被代理业务模型必须有接口,实际业务模型必须接口

         被代理的业务模型等同于实际的业务模型

动态织入:

1 package com.tarena.proxy;
  2 
  3  
  4 
  5 import java.lang.reflect.Proxy;
  6 
  7  
  8 
  9 public class JDKProxy {
 10 
 11 /**
 12 
 13  * 专门用来获取代理对象的方法,是通过jdk给提供的api来获取代理对象
 14 
 15  * @param targetObject 目标对象,就是实际业务的对象,
 16 
 17  *                     比如:UserServiceImpl类的对象 就是目标对象
 18 
 19  * @return Object obj 目标对象的代理对象,代理对象是跟目标对象是兄弟关系,
 20 
 21  *         所以目标对象所对应的类,必须有接口
 22 
 23  */
 24 
 25 public static Object getProxyObject(Object targetObject) {
 26 
 27 Object obj=null;
 28 
 29 /**
 30 
 31  * Object obj就是代理对象
 32 
 33  * 一参:目标对象的类加载器,获取到类路径
 34 
 35  * 二参:目标对象的接口,根据接口造出接口的对象
 36 
 37  * 三参:InvocationHandler接口的回调,
 38 
 39  *     实际就是实际业务和额外新功能的耦合类
 40 
 41  */
 42 
 43 obj=Proxy.newProxyInstance(
 44 
 45 targetObject.getClass().getClassLoader(),
 46 
 47 targetObject.getClass().getInterfaces(),
 48 
 49 new TransactionHandler(targetObject));
 50 
 51  
 52 
 53 return obj;
 54 
 55 }
 56 
 57 }
 58 
 59 package com.tarena.proxy;
 60 
 61  
 62 
 63 import java.lang.reflect.InvocationHandler;
 64 
 65 import java.lang.reflect.Method;
 66 
 67  
 68 
 69 import com.tarena.other.TransactionManager;
 70 
 71  
 72 
 73 public class TransactionHandler implements InvocationHandler {
 74 
 75 private Object targetObject;
 76 
 77 public TransactionHandler(Object targetObject) {
 78 
 79 this.targetObject=targetObject;
 80 
 81 }
 82 
 83 @Override
 84 
 85 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 86 
 87 Object obj=null;
 88 
 89 TransactionManager tm=new TransactionManager();
 90 
 91 try {
 92 
 93 tm.begin();
 94 
 95 //由目标对象调用实际的功能方法
 96 
 97 obj=method.invoke(targetObject, args);//targetObject.addUser();
 98 
 99 tm.commit();
100 
101 }catch(Exception e) {
102 
103 e.printStackTrace();
104 
105 tm.rollback();
106 
107 }
108 
109 return obj;
110 
111 }
112 
113  
114 
115 }
116 
117 测试方法:
118 
119 @Test
120 
121 public void testMethd2() {
122 
123 //targetObject根proxyObject是兄弟关系,是隶属于同一个接口
124 
125 //带事务管理,用动态代理方式
126 
127 UserServiceImpl targetObject=new UserServiceImpl();
128 
129  
130 
131 //送进去目标对象,出来的是代理对象
132 
133 UserService proxyObject=(UserService)JDKProxy.getProxyObject(targetObject);
134 
135 System.out.println(proxyObject.getClass());
136 
137 //是用代理对象调用方法
138 
139 proxyObject.addUser(new User());
140 
141 proxyObject.updateUser(new User());
142 
143  
144 
145 }

 

 

 

CGLIB动态代理:

     要求目标类不能是final类

动态织入:

1 package com.tarena.proxy;
  5 import java.lang.reflect.Proxy;
  9 import net.sf.cglib.proxy.Enhancer;
 13 public class CGLIBProxy {
 14 
 15 /**
 16 
 17  * 专门用来获取代理对象的方法,是通过jdk给提供的api来获取代理对象
 18 
 19  * @param targetObject 目标对象,就是实际业务的对象,
 20 
 21  *                     比如:UserServiceImpl类的对象 就是目标对象
 22 
 23  * @return Object obj 目标对象的代理对象,代理对象是跟目标对象是父子关系,
 24 
 25  *         目标对象是长辈, 代理对象小辈
 26 
 27  *         所以目标对象所对应的类,不能是final的
 28 
 29  */
 30 
 31 public static Object getProxyObject(Object targetObject) {
 32 
 33   Object obj=null;
 34 
 35   //enhancer:增强加强
 36 
 37   Enhancer enhancer=new Enhancer();
 38 
 39   enhancer.setSuperclass(targetObject.getClass());
 40 
 41   enhancer.setCallback(new TransactionInterceptory(targetObject));
 42 
 43   obj=enhancer.create();
 44 
 45   return obj;
 46 
 47   }
 48 
 49 }
 50 
 51 package com.tarena.proxy;
 55 import java.lang.reflect.Method;
 59 import com.tarena.other.TransactionManager;
 63 import net.sf.cglib.proxy.MethodInterceptor;
 65 import net.sf.cglib.proxy.MethodProxy;
 66 
 67  
 68 
 69 public class TransactionInterceptory implements MethodInterceptor{
 70 
 71 private Object targetObject;
 72 
 73 public TransactionInterceptory(Object targetObject) {
 74 
 75   this.targetObject=targetObject;
 76 
 77 }
 78 
 79 @Override
 80 
 81 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
 82 
 83   Object obj=null;
 84 
 85   TransactionManager tm=new TransactionManager();
 86 
 87  
 88 
 89 try {
 90 
 91   tm.begin();
 92 
 93   obj=method.invoke(targetObject, args);
 94 
 95   tm.commit();
 96 
 97 }catch(Exception e) {
 98 
 99   e.printStackTrace();
100 
101 }
102 
103 return obj;
104 
105 }
106 
107  
108 
109  
110 
111 }

 

 

测试方法:

    

1 @Test
 2 
 3 public void testMethd2() {
 4 
 5 //targetObject根proxyObject是父子关系
 6 
 7 //带事务管理,用动态代理方式
 8 
 9 UserServiceImpl targetObject=new UserServiceImpl();
10 
11  
12 
13 //送进去目标对象,出来的是代理对象
14 
15 UserService proxyObject=(UserService)CGLIBProxy.getProxyObject(targetObject);
16 
17 System.out.println(proxyObject.getClass());
18 
19 //是用代理对象调用方法
20 
21 proxyObject.addUser(new User());
22 
23 proxyObject.updateUser(new User());
24 
25  
26 
27 }

 

 

 

 

动态代理总结:

   实际业务跟额外的功能类还是解耦

    每一个业务都对应一个静态的代理对象

    动态代理,InvocationHandler的子实现的复用率高

    实际业务类里的所有的方法都要添加额外的功能,不能实现只给部分

         方法添加额外的功能

 

springAOP:底层还是用的动态代理

有接口,spring就用jdk生成代理对象

没有接口,spring就用CGLIB生成代理对象

 

 

springAOP中的那个几个概念

 

切面aspect:切面是一个类(功能类),类里有若干方法,每个方法代表一个功能

                把这些功能方法切到指定的位置,切到到业务方法的前后,或其他

                比如:事务的功能

 

连接点joinpoint:用代理对象打点调用方法,这句话的位置就是连接点

 

通知advice:切面类中的那些方法就是通知,

 

切入点pointcut:把切面中的通知,切到哪个类中的哪些方法上,

                         切入点是指切到哪些方法上

 

目标对象targetObject:实际的业务类的对象

 

aop代理aopproxy:由spring框架帮程序员用jdk或cglib生成代理对象

                                  这个生成的过程被spring封装了

 

织入weaving:把额外的功能织入到业务中,其他说法,叫横切