补充几个其他的写法:
@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:把额外的功能织入到业务中,其他说法,叫横切