IOC:spring核心功能之一 控制反转
主要通过 注解+反射+工厂;
写一个简易版本的IOC实现方式
定义实体类
public class User {
private String userName;
private Integer age;
public User(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [userName=" + userName + ", age=" + age + "]";
}
}
定义注解@ConponentDiy (标明是容器所管理的类 的功能)
@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME )
public @interface ComponentDiy {
/**
* @Target(ElementType.TYPE) //接口、类、枚举、注解
* @Target(ElementType.FIELD) //字段、枚举的常量
* @Target(ElementType.METHOD) //方法
* @Target(ElementType.PARAMETER) //方法参数
* @Target(ElementType.CONSTRUCTOR) //构造函数
* @Target(ElementType.LOCAL_VARIABLE)//局部变量
* @Target(ElementType.ANNOTATION_TYPE)//注解
* @Target(ElementType.PACKAGE) ///包
*/
/**
* @Retention:注解的保留位置
* @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
* @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
* @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
*/
/**
* @Document:说明该注解将被包含在javadoc中
*
* @Inherited:说明子类可以继承父类中的该注解
*/
}
定义注解@InjectDiy (自动注入功能)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectDiy {
}
演示 controller中通过注解自动注入Service对象
@ComponentDiy
public class UserController {
@InjectDiy
private UserService userService;
public void getUser(){
User usr = userService.getUsr();
System.out.println(usr);
}
}
定义Service
@ComponentDiy
public class UserService {
public User getUsr(){
User user = new User("张三",20);
return user;
}
}
核心实现功能点来了
public class IocContext {
//用以存放容器所管理的Bean
public static final Map<Class<?>,Object> applicationContext = new ConcurrentHashMap<Class<?>,Object>();
static {
//包扫描路径 相当于@ComponentScan配置的包扫描路径
String packageName = "com.example.demo";
try {
initBean(packageName);
}catch (Exception e){
e.printStackTrace();
}
}
private static void initBean(String packageName) throws Exception{
Enumeration<URL> urls =
Thread.currentThread().getContextClassLoader().
getResources(packageName.replaceAll("\\.","/"));
while (urls.hasMoreElements()){
//扫描加载指定包路径下的所有的Class,并判断该Class是否是@Component注解的类,
//如果是,则创建实例,并保存到applicationContext缓存中。
addClassByAnnotation(urls.nextElement().getPath(),packageName);
}
//IOC实现自动注入
IocUtil.inject();
}
/**
* 获取指定包下实现ComponnetDiy 的Bean实例
* @param filePath
* @param packageName
*/
private static void addClassByAnnotation(String filePath,String packageName){
try {
File[] files = getClassFiles(filePath);
if(files != null){
for(File f : files){
String fileName = f.getName();
if(f.isFile()){
Class<?> clazz = Class.forName(packageName+"."+fileName.substring(0,fileName.lastIndexOf(".")));
//判断该类是否实现了注解
if(clazz.isAnnotationPresent(ComponentDiy.class)){
applicationContext.put(clazz,clazz.newInstance());
}
}else {
addClassByAnnotation(f.getPath(),packageName+"."+fileName);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
public static File[] getClassFiles(String filePath){
return new File(filePath).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isFile() && file.getName().endsWith(".class") || file.isDirectory();
}
});
}
}
ICO工具类
public class IocUtil {
public static void inject(){
Map<Class<?>,Object> map = IocContext.applicationContext;
try {
for(Map.Entry<Class<?>,Object> entry : map.entrySet()){
Class<?> clazz = entry.getKey();
Object obj = entry.getValue();
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
if(field.isAnnotationPresent(InjectDiy.class)){
Class<?> fieldClazz = field.getType();
field.setAccessible(true);
Object fieldObj = map.get(fieldClazz);
field.set(obj,fieldObj);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
测试类:
public class Check {
public static void main(String[] args) throws Exception {
UserController userController = (UserController)IocContext.applicationContext.get(UserController.class);
userController.getUser();
}
}
打印结果如下:
Debugger解释一下
IOC示例代码参考:https://blog.csdn.net/jijianshuai/article/details/78708230
AOP实现方式
AOP好处和专业术语就不多扯了,不清楚的自行百度。
Spring的AOP实现主要有两种代理机制:
JDK动态代理:针对实现了接口的类产生代理
Cglib动态代理:针对没有实现接口的类产生代理,底层采用的字节码增强技术,生成被代理的类的子对象
先看一个例子
定义一个账户接口
public interface Count {
//查询账户
public void queryCount();
//修改账户
public void updateCount();
}
定义实现类
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("开始查询账户.......");
}
@Override
public void updateCount() {
System.out.println("开始更新账户......");
}
}
定义代理类
public class CountProxyStatic implements Count {
private CountImpl countImpl;
//覆盖构造器
public CountProxyStatic(CountImpl countImpl){
this.countImpl = countImpl; //其实就是要被增强的对象
}
@Override
public void queryCount() {
System.out.println("查询账户前置操作...");
countImpl.queryCount();
System.out.println("查询账户后置操作...");
}
@Override
public void updateCount() {
System.out.println("更新账户前置操作...");
countImpl.updateCount();
System.out.println("更新账户后置操作...");
}
}
打印结果:
* 通过这种 静态代理 实现方法前置后置增强 * 静态代理缺陷很明显,一个代理类只能对一个业务接口的实现类进行增强。 * 如果有多个业务接口,那么定义多个实现类和代理类。 * 如果代理类对业务方法的增强都是一样的,那这样的话,在多个代理类中就会存在大量重复的代码。 * 这时候我们需要定义一个代理类,它能代理所有实现类的方法调用 * 根据传进来的业务实现类和方法名进行具体调用 这就是动态代理
下面开始介绍基于JDK实现的动态代理
定义接口(JDK实现的动态代理需要有接口)
public interface Subject {
public void request();
}
定义接口实现类
public class RealSubjuect implements Subject {
@Override
public void request() {
System.out.println("来自真是客户的请求....");
}
}
定义代理类(需要实现InvocationHandler接口)
public class DynamicSubject implements InvocationHandler {
private Object obj; //其实就是被代理的对象
public DynamicSubject(){
}
public DynamicSubject(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before ........");
method.invoke(obj,args);
System.out.println("after..........");
return null;
}
}
测试方法:
public class SubjuectTest {
public static void main(String[] args) {
Subject rs = new RealSubjuect();
InvocationHandler ds = (InvocationHandler)new DynamicSubject(rs);
//生成代理
Subject subject = (Subject)Proxy.newProxyInstance(rs.getClass().getClassLoader(), rs.getClass().getInterfaces(), ds);
//证明生成的代理对象是不是Proxy的实例
System.out.println(subject instanceof Proxy);
System.out.println("subject的classs是:"+subject.getClass().toString());
System.out.print("subject中的属性有:");
Field[] fields = subject.getClass().getDeclaredFields();
for(Field f : fields){
System.out.print(f.getName()+",");
}
System.out.print("\n"+"subject中的方法有:");
Method[] methods = subject.getClass().getDeclaredMethods();
for(Method method : methods){
System.out.print(method.getName()+",");
}
System.out.println("\n" + "subject的父类是:" + subject.getClass().getSuperclass());
System.out.print("\n" + "subject实现的接口是");
Class<?>[] interfaces = subject.getClass().getInterfaces();
for (Class i :interfaces){
System.out.print(i.getName() + ",");
}
System.out.println("\n\n"+"运行结果为 :");
subject.request();
}
}
打印结果如下:
先看一个关键的方法:Proxy类中的newProxyInstance()方法
//三个参数分别是:
需要增强的对象的类加载器 需要增强的对象实现的所有接口 需要增强的对象的代理类
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
//主要通过此方法生成$proxy0对象
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
主要通过这个getProxyClass0生成$proxy对象
由此可见 通过Proxy类的newProxyInstance方法生成的是Proxy类型的对象$Proxy0(继承了Proxyl类,实现了被增强对象的接口),然后将此类强转成了Subject类。
当走到最后一步的时候
会自动跳转到代理类DynamicSubject的invoke方法中; 这一步又是怎么访问到的呢?
关键点就在于生成的代理类 $Proxy0类中
Proxy构造方法
class Proxy{
InvocationHandler h=null;
protected Proxy(InvocationHandler h) {
this.h = h;
}
...
}
$Proxy类中的代码($Proxy是动态代理内存中生成的类)
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("***.RealSubject").getMethod("request",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
} //static
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler); //在这里调用了上面的Proxy的构造方法
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void request() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
上述的h其实就是代理类DynamicSubject,
【 Subject rs = new RealSubjuect();
InvocationHandler ds = (InvocationHandler)new DynamicSubject(rs);
//生成代理
Subject subject = (Subject)Proxy.newProxyInstance(rs.getClass().getClassLoader(), rs.getClass().getInterfaces(), ds);】
在生成代理对象$Proxy0的时候已经将代理类DynamicSubject(ds)当作参数传递过去了,在$Proxy0类中的构造方法中,调用了父类Proxy的构造方法。
所以在最后一步调用request方法的时候 (subject == $Proxy 见上图)
其实就是代理对象$Proxy0 调用 request()方法的时候;
然后 super.h.invoke(this, m3, null);
就是调用到了父类Proxy的Invoke方法;即:InvocationHandler.invoke();
JDK动态代理参考:https://paddy-w.iteye.com/blog/841798
Cglib实现动态代理
定义接口
public interface EatFacade {
public void eat();
}
定义实现类
public class EatFacadeImpl implements EatFacade {
@Override
public void eat() {
System.out.println("吃美食了...");
}
}
定义增强类
public class EatFacadeCglib implements MethodInterceptor {
//其实就是业务对象类 供代理方法中进行真正的业务方法调用
private Object target;
public Object getInstance(Object target){
this.target = target; //给业务对象赋值
Enhancer enhancer = new Enhancer(); //创建加强器 用于创建动态代理类
enhancer.setSuperclass(this.target.getClass()); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
//设置回调 对于代理类上所有方法调用 都会调用Callback,而Callback则需要实现intercept()方法进行拦截
enhancer.setCallback(this);
//创建动态代理对象并返回
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("吃饭前洗手准备....");
methodProxy.invokeSuper(o,objects);
System.out.println("吃饭后漱口....");
return null;
}
}
测试代码
public static void main(String[] args) {
//动态代理cglib实现方式测试
EatFacadeImpl eatFacadeimpl = new EatFacadeImpl();
EatFacadeCglib cglib = new EatFacadeCglib();
EatFacadeImpl eatFacadeCglib = (EatFacadeImpl) cglib.getInstance(eatFacadeimpl);
eatFacadeCglib.eat();
}
结果:
关于Cglib更加深入了解可以参考:https://www.cnblogs.com/chinajava/p/5880887.html