preface

I recently wanted to learn Spring source code, a variety of design patterns used in Spring source code incisively and vividly, I have to sigh that the original majority of developers have been standing on the shoulders of the great people programming. When it comes to Spring, interviews often ask questions about its two cores, IOC and AOP. IOC is essentially a container for bean reflection and dependency injection, managing the life cycle of beans. AOP is essentially a dynamic proxy. Today I will talk about dynamic proxy. I will explain dynamic proxies from the following aspects:

  • Static agent
  • JDK dynamic proxy
  • CGlib dynamic proxy
  • Talk about my own pitfalls with AOP in real projects

Static agent

Static proxy is very simple, we will write in the code of this kind of static proxy. In simple terms, the proxy class is passed as a parameter to the proxy class constructor, allowing the proxy class to implement more powerful functions for the proxy class.

 1package com.bingo.designPatterns.proxy;

2

3/ * *

4* Description: Static proxy

5 * User: bingo

6* /


7

8public class StaticProxyTest {

9

10    public static void main(String[] args) {

11

12        UserService userService = new UserService();

13

14        LogProxy logProxy = new LogProxy(userService);

15        logProxy.addUser();

16        logProxy.deleteUser();

17    }

18}

19

20interface IUserService{

21    void addUser(a);

22    void deleteUser(a);

23}

24

25

26class UserService implements IUserService{

27

28    @Override

29    public void addUser(a) {

30        System.out.println("Add user");

31    }

32

33    @Override

34    public void deleteUser(a) {

35        System.out.println("Delete user");

36    }

37}

38

39// Log agent

40class LogProxy implements IUserService{

41

42    / / the target class

43    private UserService target;

44

45    public LogProxy(UserService target){

46        this.target = target;

47    }

48

49    @Override

50    public void addUser(a) {

51        System.out.println("Logging started");

52        target.addUser();

53        System.out.println("Logging finished");

54    }

55

56    @Override

57    public void deleteUser(a) {

58        System.out.println("Logging started");

59        target.deleteUser();

60        System.out.println("Logging finished");

61    }

62}

Copy the code

Although static proxy implementation is relatively simple, in actual projects we need to write a proxy class for each class, which requires a lot of redundant code, which is not conducive to code decoupling and extension. Dynamic proxies, however, solve the above problem by truly decoupling the business logic code from the enhanced functionality code.

A dynamic proxy

There are two main dynamic proxies used in Spring source code, JDK dynamic proxy and CGLib dynamic proxy. The main differences between the two are:
  • JDK dynamic proxies typically generate proxies for classes that implement interfaces. (This can be better understood when talking about pits encountered with AOP.)
  • If the target object does not implement an interface, the CGLIB proxy is used by default. If the target object implements the interface, it can be forced to use the CGLIB implementation proxy (adding the CGLIB library).
Similarities:
  • Both dynamic proxies are essentially bytecode assemblies
Application scenarios of AOP dynamic proxy:
  • The log
  • The transaction
  • permissions
  • The cache
  • Lazy loading

JDK dynamic proxy

JDK dynamic proxy proxy classes typically need to implement interfaces

 1package com.bingo.designPatterns.proxy;

2

3import java.lang.reflect.InvocationHandler;

4import java.lang.reflect.Method;

5import java.lang.reflect.Proxy;

6

7/ * *

8* Description: JDK dynamic proxy

9 * User: bingo

10* /


11public class JdkProxyTest {

12

13    public static void main(String[] args) {

14        IPersonService personService = JdkDynamicProxy.getProxy();

15        personService.addPerson();

16        personService.deletePerson();

17    }

18}

19

20interface IPersonService{

21    void addPerson(a);

22    void deletePerson(a);

23}

24

25class PersonService implements IPersonService{

26    @Override

27    public void addPerson(a) {

28        System.out.println("Add people");

29    }

30

31    @Override

32    public void deletePerson(a) {

33        System.out.println("Delete people");

34    }

35}

36

37

38/ * *

39* newProxyInstance

40* ClassLoader loader: specifies the ClassLoader used by the current target object. The method for obtaining the loader is fixed

41* Class<? >[] interfaces: Specifies the type of the interface implemented by the target object, using generics to confirm the type

42InvocationHandler: Specifies the dynamic handler that fires the event handler's method when executing the target object's method

43* /


44class JdkDynamicProxy{

45

46    public static IPersonService getProxy(a){

47

48        IPersonService personService = new PersonService();

49

50        IPersonService proxy = (IPersonService) Proxy.newProxyInstance(IPersonService.class.getClassLoader(), newClass<? >[]{IPersonService.class},new InvocationHandler() {

51

52            @Override

53            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

54                System.out.println("Logging started");

55                Object obj = method.invoke(personService, args);

56                System.out.println("Logging finished");

57                return obj;

58            }

59        });

60

61        return proxy;

62    }

63}

Copy the code

CGLib dynamic proxy

You need to import the cglib.jar, asm.jar package to use this agent

 1package com.bingo.designPatterns.proxy;

2

3import net.sf.cglib.proxy.Enhancer;

4import net.sf.cglib.proxy.MethodInterceptor;

5import net.sf.cglib.proxy.MethodProxy;

6

7import java.lang.reflect.Method;

8

9/ * *

10* Description: Cglib dynamic proxy

11 * User: bingo

12* /


13

14public class CglibProxyTest {

15    public static void main(String[] args) {

16

17        CglibProxy proxy = new CglibProxy();

18        Train t = (Train)proxy.getProxy(Train.class);

19        t.move();

20    }

21}

22

23class Train {

24

25    public void move(a){

26        System.out.println("The train is moving...");

27    }

28}

29

30class CglibProxy implements MethodInterceptor {

31

32    private Enhancer enhancer = new Enhancer();

33

34    public Object getProxy(Class clazz){

35        // Set the class to create the subclass

36        enhancer.setSuperclass(clazz);

37        enhancer.setCallback(this);

38

39        return enhancer.create();

40    }

41

42    / * *

43Intercepts all calls to target class methods

44* obj an instance of the target class

45* m Reflection object of the target method

46* Arguments to the args method

47* proxy Instance of the proxy class

48* /


49    @Override

50    public Object intercept(Object obj, Method m, Object[] args,

51                            MethodProxy proxy)
 throws Throwable 
{

52        System.out.println("Log start...");

53        // The proxy class calls the parent class's methods

54        proxy.invokeSuper(obj, args);

55        System.out.println("Log end...");

56        return null;

57    }

58}

Copy the code

Potholes encountered in projects using AOP

Problems encountered by the author in the development of applets service interface: 1. The transaction manager is configured in the Spring configuration file, as follows:

1<! -- Transaction manager configuration, single data source transaction -->

2<tx:annotation-driven transaction-manager="transactionManager" />  

3<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

4    <property name="dataSource" ref="dataSource" />

5</bean>

Copy the code

2. After configuring the transaction manager, add the @Transactional annotation

1@Service

2@Transactional

3public class AccountService{

4    //to do something

5}

Copy the code

At first glance, there was nothing wrong with this configuration and use, right? But as soon as the project was put into the Tomcat service, there was an error. I can’t remember exactly what error was reported, but I do remember that the error was caused by the transaction annotation. I found that various configurations were not bad, and I did not know where the problem was. But the original project started normally, but my project reported an error. A closer look reveals that services in the company’s original projects defined an interface as a specification, and the @Transactional annotation was added to the interface implementation class. As a result, I vaguely define an interface specification for each Service class that implements the @Transactional annotation as follows:

1@Service

2@Transactional

3public class AccountService implements IAccountService {

4    //to do something

5}

Copy the code

The configuration remains the same, you simply define and implement the interface for the Service layer, and the project runs fine.

What is the root of the problem? Here it is:
1<tx:annotation-driven transaction-manager="txManager"/>

Copy the code

JDK dynamic proxies are enabled by default. The JDK can only proxy interfaces, not classes. My project uses this configuration, but the project starts with an error because the Service interface is not defined.

To use the CGLIB dynamic proxy, perform the following configuration:

1<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/> 

Copy the code

I don’t know if any readers have encountered the same problem as me, but if you don’t understand dynamic proxies, you might have the same problem. However, it is very important to write program specifications. In the MVC three-tier structure, except the Controller layer, the Service and Dao layer all need to define interfaces, which are the specifications developed by enterprises. At the time was a just graduate interns, hard to avoid can sometimes write this non-standard code, but hope I can be more and more specification, see the alibaba Java development’s handbook, look at the source code, see Daniel to write code, believe oneself also can write soon so elegant code, programming into a kind of art.

I am Xiaobin, a Java programmer in Guangzhou. I just graduated for half a year and have been devoted to learning Java. If you are interested in my article, you can follow my wechat official account (J2 Binbin).