1 获取Class对象三种方式
//1 对象的静态方法
Class clazz1 = Person.class;
//2 最常用的方式
Class<?> clazz2 = Class.forName(“reflect.Person”);
//3 如果有对象了,可以使用这种方式
Person person = new Person();
Class<? extends Person> clazz3 = person.getClass();
//4 通过类加载器加载(不常用)
Class<?> clazz4 = ClassLoader.getSystemClassLoader().loadClass(“reflect.Person”);
由于反射一般使用在运行时并不知道是那种类型,因此(1,3)并不常用,对象都已经存在了,此时就没有必要用到反射了
2 运用
//getMethods 获取所有的公有方法
//getMethod 获取的公有方法
//getDeclaredMethods 获取所有私有的方法
//getDeclaredMethod 获取私有的方法
//setAccessible(true) 解除私有限定
//获取构造器数组 按照类中的定义的顺序
Constructor<?>[] constructors = clazz.getConstructors();
3 动态代理
AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。
3.1 jdk动态代理
jdk动态代理是jdk原生就支持的一种代理方式,它的实现原理,就是通过让target类和代理类实现同一接口,代理类持有target对象,来达到方法拦截的作用,这样通过接口的方式有两个弊端,一个是必须保证target类有接口,第二个是如果想要对target类的方法进行代理拦截,那么就要保证这些方法都要在接口中声明,实现上略微有点限制。
public interface GoodsService {
public void sale();
public void show();
}
public class GoodsServiceImpl implements GoodsService {
@Override
public void sale() {
System.out.println("我有商品要卖");
}
@Override
public void show() {
System.out.println("展示商品。。");
}
}
public static void fun1(){
GoodsServiceImpl goodsService = new GoodsServiceImpl();
GoodsService proxy = (GoodsService)Proxy.newProxyInstance(GoodsServiceImpl.class.getClassLoader(),
GoodsServiceImpl.class.getInterfaces(),new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是商品的代理商");
Object invoke = method.invoke(goodsService, args);
System.out.println("完了");
return invoke;
}
});
proxy.sale();
}
上面的方式会对所有的方法进行代理
public class MyInvocationHandler implements InvocationHandler {
private Object object;
MyInvocationHandler() {
super();
}
public MyInvocationHandler(Object o){
object = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
if (Objects.equals(method.getName(),"sale()")){
System.out.println("代理卖东西。。。");
invoke = method.invoke(object);
}else {
method.invoke(object);
}
return invoke;
}
}
public static void fun2(){
GoodsServiceImpl goodsService = new GoodsServiceImpl();
GoodsService proxyInstance = (GoodsService)Proxy.newProxyInstance(goodsService.getClass().getClassLoader(),
goodsService.getClass().getInterfaces(), new MyInvocationHandler(goodsService));
proxyInstance.show();
}
}
将代理的方法分离出来
3.2 cglib动态代理实现
cglib 代理不需要目标类继承一个接口, 是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口
public class TargetService {
public void save(){
System.out.println("do someting ...");
}
}
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(){
super();
}
public ProxyFactory(Object object){
target = object;
}
public Object getProxyInstance(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务。。。");
Object invoke = method.invoke(target, objects);
System.out.println("提交事务。。。");
return invoke;
}
}
public class CglibTest {
public static void main(String[] args) {
TargetService targetService = new TargetService();
ProxyFactory proxyFactory = new ProxyFactory(targetService);
TargetService proxyInstance = (TargetService)proxyFactory.getProxyInstance();
proxyInstance.save();
}
}
4、需要注意的问题
需要注意的是,当一个方法没有被aop事务包裹,在该方法内部去调用另外一个有aop事务包裹的方法时,这个方法的aop事务不会生效。
public void register() {
aopRegister();
}
@Transactional
public void aopRegister() {
}
因为通过上面的分析我们知道,在spring中,无论通过jdk的形式还是cglib的形式,代理类对target对象的方法进行拦截,其实都是通过让代理类持有target对象的引用,当外部引用aop包围的方法时,调用的其实是代理类对应的方法,代理类持有target对象,便可以控制target方法执行时的全方位拦截。
而如果在target的内部方法register调用一个aop包围的target方法aopRegister,调用的其实就是target自身的方法,因为这时候的this指针是不可能指向代理类的。所以事务是不能生效的。