Analysis principles and examples of spring, IOC and AOP

Reprinted from http://blog.sina.com.cn/s/blog_624a352c0101fo9j.html
About spring IOC Analysis principles and examples of spring, IOC and AOP

 During this period of time, I have also read the books related to spring, and there are also After a rough and preliminary understanding and understanding, although I have always heard that spring is a very good open source framework, I have never had the opportunity to learn and use it (is it a bit outdated? Ha ha), so I will focus on learning during this time. After spring (one week is of course entry-level~~)

  everyone has been talking about how powerful spring's IOC is, in fact, I don't think it is how powerful IOC is. To put it bluntly, IOC is actually very simple. Let's start with IOC. This concept is actually the opposite of our usual new object. When we usually use an object, we usually directly use the keyword class to create an object. What's the harm in this? In fact, it is obvious that using new means that the current module has been unknowingly coupled with the new object, and we usually call the underlying implementation module from a higher-level abstract module, which results in a module that depends on the specific The realization of this is in conflict with the interface-oriented abstraction-oriented programming advocated in our JAVA, and doing so also brings about the problem of the system's module architecture. For a very simple example, when we operate the database, the business layer always calls the DAO layer. Of course, our DAO is generally developed using interfaces, which satisfies the loose coupling to a certain extent, so that the business logic layer does not depend on the DAO layer. The specific database DAO layer. However, when we use it, we will still create a new DAO layer of a specific database, which is also bound to a specific database invisibly. Although we can use the abstract factory pattern to obtain the DAO implementation class, unless we put all the database's data at once DAO is written out, otherwise we still have to modify the DAO factory class when migrating the database.

  So what can we achieve with IOC? IOC means that the implementation of the DAO interface is no longer obtained by the business logic layer calling the factory class, but through the container (such as spring) to automatically set the DAO implementation class for our business layer. In this way, the whole process is reversed. In the past, our business layer took the initiative to obtain DAO, but now DAO is actively set to the business logic layer, which is the origin of the reversal of control. Through IOC, we can seamlessly implement database replacement and migration without modifying any code. Of course, the premise is that we must write a DAO that implements a specific database. We generalize DAO to more situations, then IOC brings us greater convenience. For example, for multiple implementations of an interface, we only need to configure it and it will be ok instead of writing factories one by one. Come and get it. This is the loose coupling of modules and the convenience of application that IOC brings us.

  So why is IOC simple? To put it bluntly, it is actually a transition from our usual new to using reflection to obtain class instances. I believe that anyone who can use java's reflection mechanism, then it is not impossible to write an IOC framework by themselves. For example:

...
public ObjectgetInstance(String className) throws Exception
{
  Object obj = Class.forName(className).newInstance();
  Method[] methods = obj.getClass().getMethods();
  for (Method method : methods) {
    if (method.getName().intern() == "setString") {
      method.invoke(obj, "hello world!");
    }
  }
}
...

  In the above method, we simply use the setString method of reflection for the specified class to set a hello world! string. In fact, you can see that the IOC is really simple. Of course, the simplicity of the IOC does not mean that the spring's IOC is simple. The power of the spring's IOC lies in a series of very powerful configuration file maintenance classes, which can maintain each of the spring configuration files. The relationship between classes, this is where spring's IOC is really powerful. In spring's bean definition file, you can not only set properties for defining beans, but also support functions such as inheritance between beans, abstraction of beans, and different acquisition methods.

  Next time, I will share with you the relevant experience of spring's bean configuration. If it is not good, you can give your opinion, but don't be rotten eggs, hehe~~~~ 


2. About spring aop

reflection implementation AOP dynamic proxy mode (the implementation principle of Spring AOP)
has not used Spring for a long time. I suddenly picked up the book. I found that I am not familiar with AOP.
In fact, AOP means aspect-oriented programming.
OO focuses on us The method to solve the problem (encapsulated into Method), and AOP focuses on the common points of many methods to solve the problem, which is a supplement to the OO idea!
Let's take an example that people often give to explain:
for example, There are many business methods in an application we are going to develop now, but now we want to monitor the execution of this method in full or in part. Maybe we will add a log record before some methods,
we write Let's take an example to see our simplest solution.
Let 's write an interface IHello.java code as follows:
1package sinosoft.dj.aop.staticaop;
2 3
public interface IHello {
4    
8 void sayHello(String name);
9}
10
there is a method for inputting "Hello" and the name passed in; let's write a class to implement IHello interface
package sinosoft.dj.aop.staticaop;

public class Hello implements IHello {

    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }

}

Now we need to add logging to this business method What will we do without changing the original code? Maybe, you will write a class to implement the IHello interface and rely on the Hello class. The code is as follows:
1package sinosoft.dj.aop.staticaop ;
2 3
public class HelloProxy implements IHello {
4 private IHello hello;
5
6 public HelloProxy(IHello hello) {
7        this.hello = hello;
8    }
9
10    public void sayHello(String name) {
11        Logger.logging(Level.DEBUGE, "sayHello method start.");
12        hello.sayHello(name);
13        Logger.logging(Level.INFO, "sayHello method end!");
14
15    }
16
17}
18
其中.Logger类和Level枚举代码如下:
Logger.java
1package sinosoft.dj.aop.staticaop;
2
3import java.util.Date;
4
5public class Logger{
6    
11    public static void logging(Level level, String context) {
12        if (level.equals(Level.INFO)) {
13 System.out.println(new Date().toLocaleString() + " " + context);
14 }
15 if (level.equals(Level.DEBUGE)) {
16 System.err.println(new Date() + " " + context);
17 }
18 }
19
20}
21Level.java

1package sinosoft.dj.aop.staticaop;
2
3public enum Level {
4 INFO,DEBUGE;
5} 6Then
let's write a test class to see, the code is as follows:
Test.java
1package sinosoft.dj.aop.staticaop;
2
3public class Test {
4 public static void main(String[] args) {
5 IHello hello = new HelloProxy(new Hello());
6 hello.sayHello("Doublej" );
7 }
8}
9 Running the above code we can get the following result:

Tue Mar 04 20:57:12 CST 2008 sayHello method start.
Hello Doublej
2008-3-4 20:57:12 sayHello method end!
From the above code we can It can be seen that the hello object is created by the so-called proxy state of HelloProxy. In this way, if we want to remove the logging function in the future, then we only need to change the code to get the hello object to the following:
1package sinosoft.dj.aop. staticaop;
2
3public class Test {
4 public static void main(String[] args) {
5 IHello hello = new Hello();
6 hello.sayHello("Doublej");
7 }
8}
9 The
above code can be said to be AOP Simplest implementation!
But we will find a problem, if we have a lot of classes like Hello, then, are we going to write a lot of classes like HelloProxy? Yes, yes. In fact, it is also a very troublesome thing. In jdk1. 3. After .jdk provides us with an API java.lang.reflect.InvocationHandler class. This class allows us to dynamically do something for some methods when the JVM calls the methods of a certain class. Let us put the above code Change it to see the effect.
Similarly, we write an IHello interface and a Hello implementation class. In the interface, we define two methods; the code is as follows:

IHello.java
1package sinosoft.dj.aop.proxyaop;
2
3public interface IHello {
4    
8 void sayHello(String name);
9    
13 void sayGoogBye(String name);
14}
15

Hello.java

1package sinosoft.dj.aop.proxyaop;
2
3public class Hello implements IHello {
4
5 public void sayHello(String name ) {
6 System.out.println("Hello " + name);
7 }
8 public void sayGoogBye(String name) {
9 System.out.println(name+" GoodBye!");
10 }
11}
12
We also write a proxy class. Just let this class implement java.lang .reflect.InvocationHandler interface, the code is as follows:
1package sinosoft.dj.aop.proxyaop;
2
3import java.lang.reflect.InvocationHandler;
4import java.lang.reflect.Method;
5import java.lang.reflect.Proxy;
6
7public class DynaProxyHello implements InvocationHandler {
8
9    
12 private Object delegate;
13
14    
21 public Object bind(Object delegate) {
22 this.delegate = delegate;
23 return Proxy.newProxyInstance(
24 this.delegate.getClass().getClassLoader(), this.delegate
25 .getClass().getInterfaces(), this);
26 }
27    
31 public Object invoke(Object proxy, Method method, Object [] args)
32 throws Throwable {
33 Object result = null;
34 try {
35 //Log before executing the original method
36 Logger.logging(Level.DEBUGE, method.getName() + " Method end .");
37           
38 //JVM executes the original method through this statement (reflection mechanism)
39 result = method.invoke(this.delegate, args);
40 //Record the log after executing the original method
41 Logger.logging(Level.INFO, method.getName() + "Method Start!");
42 } catch (Exception e) {
43 e.printStackTrace();
44 }
45 //Return the return value of the method to the caller
46 return result;
47 }
48
49}
50
The Logger class and Level enumeration in the above class are still the same as the implementation of the previous example. The code will not be posted here.

Let's write a Test class to test it. The code is as follows:
Test.java
1package sinosoft.dj.aop.proxyop;
2
3public class Test {
4 public static void main(String[] args) {
5 IHello hello = (IHello)new DynaProxyHello().bind(new Hello() );
6 hello.sayGoogBye("Double J");
7 hello.sayHello("Double J");
8       
9 }
10}
11
The result of running the output is as follows:
Tue Mar 04 21:24:03 CST 2008 sayGoogBye Method end .
Double J GoodBye!
2008-3-4 21:24:03 sayGoogBye Method Start!
Tue Mar 04 21:24 :03 CST 2008 sayHello Method end .
Hello Double J
2008-3-4 21:24:03 sayHello Method Start!
Due to threading, the start of the second method occurs before the end of the first method. This is not what we Attention!
We can see from the above example. As long as you are using interface-oriented programming, then it is possible to add logging operations before any method of your object is executed. He (DynaPoxyHello) automatically goes to the proxy to execute the For each method in the proxy object (Hello), a java.lang.reflect.InvocationHandler interface decouples our proxy object and the proxy object. However, we found that there is still another problem, this DynaPoxyHello object can only be used with Let's add logging operations before and after the method. Can we decouple the DynaPoxyHello object from the log operation object (Logger)?
The result is yes. Let's analyze our requirements.
Add the log operation code (or other operation code) before or after the method,
Then, we can abstract an interface, there are only two methods in this interface, one is the method that is executed before the proxy object executes the method, we name it start, and the second method is after the proxy object executes the method The method to execute is named end. The interface is defined as follows:
1package sinosoft.dj.aop.proxyaop;
2
3import java.lang.reflect.Method;
4
5public interface IOperation {
6    
10 void start(Method method);
11    
15 void end(Method method);
16}
17
Let's write a class that implements the above interface. We make it his real operator, as follows is a class of the log operator:
LoggerOperation.java
package sinosoft.dj.aop.proxyop;

import java.lang.reflect.Method;

public class LoggerOperation implements IOperation {

    public void end(Method method) {
        Logger.logging(Level.DEBUGE, method.getName() + " Method end .");
    }

    public void start(Method method) {
        Logger.logging(Level.INFO, method.getName() + " Method Start!");
    }

}

Then we need to change the code in the proxy object DynaProxyHello. As follows:
1package sinosoft.dj .aop.proxyaop;
2
3import java.lang.reflect.InvocationHandler;
4import java.lang.reflect.Method;
5import java.lang.reflect.Proxy;
6
7public class DynaProxyHello implements InvocationHandler {
8    
11 private Object proxy;
12    
15 private Object delegate;
16
17    
24 public Object bind(Object delegate,Object proxy) {
25       
26 this.proxy = proxy;
27 this.delegate = delegate;
28 return Proxy.newProxyInstance(
29 this.delegate.getClass().getClassLoader(), this.delegate
30.getClass().getInterfaces(), this);
31 }
32    
36 public Object invoke( Object proxy, Method method, Object[] args)
37 throws Throwable {
38 Object result = null;
39 try {
40 //Get the instance of the operator by reflection
41 Class clazz = this.proxy.getClass();
42 //Get it by reflection Operator's Start method
43 Method start = clazz.getDeclaredMethod("start",
44 new Class[] { Method.class });
45 //Reflect to execute the start method
46 start.invoke(this.proxy, new Object[] { method });
47 //Execute the original method of the object to be processed
48 result = method.invoke(this.delegate, args);
49// Reflect the operator's end method
50 Method end = clazz.getDeclaredMethod("end",
51 new Class[] { Method.class });
52// Execute end method by reflection
53 end.invoke(this.proxy, new Object[] { method }) ;
54
55 } catch (Exception e) {
56 e.printStackTrace();
57 }
58 return result;
59 }
60
61}
62
Then we change the code in Test.java. Test it:
package sinosoft.dj.aop .proxyaop;

public class Test {
    public static void main(String[] args) {
        IHello hello = (IHello)new DynaProxyHello().bind(new Hello(),new LoggerOperation());
        hello.sayGoogBye("Double J");
        hello .sayHello("Double J");
       
    }
}
The result is still the same.

If you want to add logging before each method, but not after the method. You can change the LoggerOperation class to the following:
1package sinosoft .dj.aop.proxyop;
2
3import java.lang.reflect.Method;
4
5public class LoggerOperation implements IOperation {
6
7 public void end(Method method) {
8 //Logger.logging(Level.DEBUGE, method.getName() + "Method end .");
9 }
10
11 public void start(Method method) {
12 Logger.logging(Level.INFO, method.getName() + "Method Start!");
13 }
14
15}
16
Run it. You will find that after each method there is no The log is recorded. In this way, we decouple the agent and the operator!

Let me leave a question for you. If we don't want all methods to be logged, how should we decouple it?
My idea is in The public Object invoke(Object proxy, Method method, Object[] args) method of the proxy object adds an if() to judge the name of the method passed in, and the judgment condition exists in XML. In this way, we can configure the file The time line is decoupled. If interested friends can configure the operator and the agent through the configuration file, then you can write a simple SpringAOP framework.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326865742&siteId=291194637
Recommended