Showing posts with label Spring AOP. Show all posts
Showing posts with label Spring AOP. Show all posts

Wednesday, April 27, 2016

Spring Transaction Isolation Level

Spring Transaction Isolation Level

The standard levels are 2,3,4,5, the higher level, the poorer concurrency/effi
  1. ISOLATION_DEFAULT (Spring)
    This is a PlatformTransactionManager Default isolation level, using Default Database transaction level. The other 4 are correspond to JDBC isolation level
  2. ISOLATION_READ_UNCOMMITTED
    Lowest isolation level. Allow other transaction to see the data from this transaction. This level can cause dirty read, non-repeatable read, and illusion read
  3. ISOLATION_READ_COMMITTED (normally used)
    Promise other transaction can read data until this transaction committed.
  4. ISOLATION_REPEATABLE_READ
    Prevent dirty read, non-repeatable read. But can illusion read.
  5. ISOLATION_SERIALIZABLE
    This is most expensive level, but most reliable. It promise Sequence. Prevent dirty read, non-repeatable read, and illusion read

Transaction Definition

Transaction Definition

  1. PROPAGATION_REQUIRED (normally used)
    If transaction existed, use it, otherwise open a new transaction
  2. PROPAGATION_SUPPORTS
    If transaction existed, use it, otherwise run as non-transaction
  3. PROPAGATION_MANDATORY
    If transaction existed, use it, otherwise throw Exception
  4. PROPAGATION_REQUIRES_NEW
    Always open a new transaction, if transaction existed, hang up the existed transaction
  5. PROPAGATION_NOT_SUPPORTED
    Always run without transaction, if transaction existed, hang up the existed transaction
  6. PROPAGATION_NEVER
    Always run without transaction, if transaction existed, throw Exception
  7. PROPAGATION_NESTED (in Spring)
    If transaction existed, run nested transaction inside the existed transaction.
    If no transaction existed, run as PROPAGATION_REQUIRED

PropagationT1 NoneT1 Existed
REQUIREDT2=>newT1
SUPPORTST2 NoneT1
MANDATORYT2 ExceptionT1
REQUIRES_NEWT2=>newT2=>new
NOT_SUPPORTEDNoneHang up T1
NEVERNoneT2 Exception
NESTEDAs REQUIREDNested

Dynamic Proxy: JDK VS CGLIB

If target object implements interface, by default, spring will use Dynamic Proxy from JDK for AOP.
If target object implements interface, we can force to use CGLIB to make Dynamic Proxy for AOP.
If target object does not implements interface, we MUST use CGLIB to make Dynamic Proxy for AOP.

In conclusion:
JDK can only apply to class which implements interface
CGLIB can apply to class with/without implementing interface

Spring will dynamically choose to use JDK or CGLIB for each target object.


JDK proxy example:
userManager $Proxy2  (id=42)
h JdkDynamicAopProxy  (id=54)

CGLIB example:
UserManagerImpl$$EnhancerBySpringCGLIB$$7f895f28  (id=46)

You can see CGLIB extends the target class to generate proxy, JDK did not
Because CGLIB do extends, our target class should NOT be final

to Enable CGLIB:

dependency:
<dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>3.2.2</version>
</dependency>

applicationContext.xml config

<!-- proxy-target-class="true" means force to use CGLIB -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

But if we want spring to choose for us, we don't have to force to do the config, just add dependency.






Tuesday, April 26, 2016

Spring AOP AspectJ Advice

An advice is really simple,
If config it in xml:
package com.gvace.aop;

/*
 * To define an Aspect
 * 
 */
public class SecurityHandler {

 private void checkSecurity() {
  System.out.println("Runned checkSecurity");
 }
}


If with Annotation
package com.gvace.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;


/*
 * To define an Aspect
 * 
 */
@Aspect
public class SecurityHandler {
 //@Pointcut Describe the target functions
 //So this function is ONLY JUST A FLAG, it will NEVER be called anyway
 //(* add*(..)), means return any type, name likes "add*", parameter can be anything 
 // the addAddMethod function does not want parameter and return type
 @Pointcut("execution(* add*(..))")
 private void addAddMethod(){}
 
 
 //define this Advice is run before target function
 //And it applied to some @Pointcut described functions
 @Before(value = "addAddMethod()")
 //@After(value = "addAddMethod()")
 private void checkSecurity() {
  System.out.println("Runned checkSecurity");
 }
}



Add a JoinPoint argument to get target class method information
package com.gvace.aop;

import org.aspectj.lang.JoinPoint;

/*
 * To define an Aspect
 * 
 */
public class SecurityHandler {
 //add a JoinPoint argument to get target class method information

 private void checkSecurity(JoinPoint joinPoint){
  System.out.println("Method name: "+joinPoint.getSignature().getName());
  for(int i=0; i<joinPoint.getArgs().length; i++){
   System.out.println(joinPoint.getArgs()[i]);
  }
  System.out.println("Runned checkSecurity");
 }
}

Spring AOP AspectJ Pointcut Expression


any public functions
any return type
any function name
any/no arguments
execution(public * *(..))


Any public functions which name start with "set"
execution(* set*(..))

All ABCService interface's function
execution(* com.abc.ABCService.*(..))

All functions classes in package abc
execution(* com.abc.*.*(..))


All functions classes in package abc or sub-package of abc
execution(* com.abc..*.*(..))


can use "||"  "&&" like
execution(* set*(..)) && execution(* com.abc.*.*(..))


More See this
http://howtodoinjava.com/spring/spring-aop/writing-spring-aop-aspectj-pointcut-expressions-with-examples/

Spring AOP with AspectJ no Annotation config

Concepts

Cross Cutting Concern: A isolated service, across all procedure in system

Aspect: The model pattern of Cross Cutting Point

Advice: The implementation of Aspect

Pointcut: Defines which JoinPoint(s) applied by Advice. For Spring, it's function invoke.

JoinPoint: the time point when Advice run, Spring only support JoinPoint on function

Weave: Apply Advice to Target Object called Weave. Spring support dynamic Weave.

Target Object: The Target Object that Advice applied to.

Proxy: Spring AOP default uses dynamic proxy from JDK, it's proxy is created when running. It can also use CGLIB proxy(when not using Interface).

Introduction: Add function for Class dynamically


See this first: Spring AOP
 http://gvace.blogspot.com/2016/03/aop.html

To skip this and see: Spring AOP with AspectJ and Annotation
http://gvace.blogspot.com/2016/04/spring-aop-with-annotation.html

Example

Using Spring Version 4.2.5
Add dependency AspectJ

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>spring_static_proxy</groupId>
 <artifactId>spring_static_proxy</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <build>
  <sourceDirectory>src</sourceDirectory>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
     <source>1.7</source>
     <target>1.7</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.build.mainClass>com.gvace.main</project.build.mainClass>
  <java.version>1.7</java.version>
  <spring.version>4.2.5.RELEASE</spring.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aop</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-beans</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
  </dependency>
  <dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.2</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>1.8.9</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.8.9</version>
  </dependency>
 </dependencies>
 <repositories>
  <repository>
   <id>spring-milestones</id>
   <name>Spring Milestones</name>
   <url>https://repo.spring.io/libs-milestone</url>
   <snapshots>
    <enabled>false</enabled>
   </snapshots>
  </repository>
 </repositories>
</project>

Create a class as Aspect

SecurityHandler.java
package com.gvace.aop;

/*
 * To define an Aspect
 * 
 */
public class SecurityHandler {

 private void checkSecurity() {
  System.out.println("Runned checkSecurity");
 }
}


An example interface(Target Object)
package com.gvace.inter;

public interface UserManager {
 public void addUser(String username,String password);
 public void delUser(int userId);
 public String findUserById(int userId);
 public void modifyUser(int userId, String username,String password);
}


The implementation of the interface(Target Object)

UserManagerImpl.java
package com.gvace.impl;

import com.gvace.inter.UserManager;

// each method have to call checkSecurity()
// and you don't want to change it based on requirement changes(like the codes being comment out)
public class UserManagerImpl implements UserManager {

 @Override
 public void addUser(String username, String password) {
  //checkSecurity();
  System.out.println("addUser:"+username+" "+password);
 }

 @Override
 public void delUser(int userId) {
  //checkSecurity();
  System.out.println("delUser:"+userId+" ");
 }

 @Override
 public String findUserById(int userId) {
  //checkSecurity();
  System.out.println("findUserById:"+userId+" ");
  return "findUserById"+userId;
 }

 @Override
 public void modifyUser(int userId, String username, String password) {
  //checkSecurity();
  System.out.println("modifyUser:"+userId+" "+username+" "+password);
 }
 /*
 public void checkSecurity(){
  System.out.println("Runned checkSecurity");
 }
 */
}


Register beans and aspect annotation

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/aop/spring-tx.xsd">
 
 <!-- Data Source -->
 <bean id="userManager" class="com.gvace.impl.UserManagerImpl"></bean>
 
 <!-- Aspect Class-->
 <bean id="securityHandler" class="com.gvace.aop.SecurityHandler"></bean>
 <aop:config>
  <!-- Define Aspect, link to Aspect Class -->
  <aop:aspect id="securityAspect" ref="securityHandler">
   <!-- Define Pointcut -->
   <aop:pointcut id="addAddMethod" expression="execution(* add*(..))"/>
   <!-- Link the Advice method to Pointcut -->
   <aop:before method="checkSecurity" pointcut-ref="addAddMethod"/>
  </aop:aspect>
 </aop:config>
</beans>



Test to run

Client.java
package com.gvace.test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gvace.inter.UserManager;

public class Client {
 public static void main(String[] args){
  BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserManager userManager = (UserManager)factory.getBean("userManager");
  //Since this UserManager interface contains function like execution(* add*(..))
  //this userManager reference will not be the implementation class, it will be a Proxy
  userManager.addUser("a", "b");
 }
}













Spring AOP with AspectJ and Annotation

Concepts

Cross Cutting Concern: A isolated service, across all procedure in system

Aspect: The model pattern of Cross Cutting Point

Advice: The implementation of Aspect

Pointcut: Defines which JoinPoint(s) applied by Advice. For Spring, it's function invoke.

JoinPoint: the time point when Advice run, Spring only support JoinPoint on function

Weave: Apply Advice to Target Object called Weave. Spring support dynamic Weave.

Target Object: The Target Object that Advice applied to.

Proxy: Spring AOP default uses dynamic proxy from JDK, it's proxy is created when running. It can also use CGLIB proxy(when not using Interface).

Introduction: Add function for Class dynamically


See this first: Spring AOP
 http://gvace.blogspot.com/2016/03/aop.html

Then see this Spring AOP with AspectJ with no Annotation Config
http://gvace.blogspot.com/2016/04/spring-aop-with-aspectj-no-annotation.html


Example

Using Spring Version 4.2.5
Add dependency AspectJ

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>spring_static_proxy</groupId>
 <artifactId>spring_static_proxy</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <build>
  <sourceDirectory>src</sourceDirectory>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
     <source>1.7</source>
     <target>1.7</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.build.mainClass>com.gvace.main</project.build.mainClass>
  <java.version>1.7</java.version>
  <spring.version>4.2.5.RELEASE</spring.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aop</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-beans</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
  </dependency>
  <dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.2</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>1.8.9</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.8.9</version>
  </dependency>
 </dependencies>
 <repositories>
  <repository>
   <id>spring-milestones</id>
   <name>Spring Milestones</name>
   <url>https://repo.spring.io/libs-milestone</url>
   <snapshots>
    <enabled>false</enabled>
   </snapshots>
  </repository>
 </repositories>
</project>

Create a class as Aspect

SecurityHandler.java
package com.gvace.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;


/*
 * To define an Aspect
 * 
 */
@Aspect
public class SecurityHandler {
 //@Pointcut Describe the target functions
 //So this function is ONLY JUST A FLAG, it will NEVER be called anyway
 //(* add*(..)), means return any type, name likes "add*", parameter can be anything 
 // the addAddMethod function does not want parameter and return type
 @Pointcut("execution(* add*(..))")
 private void addAddMethod(){}
 
 
 //define this Advice is run before target function
 //And it applied to some @Pointcut described functions
 @Before(value = "addAddMethod()")
 //@After(value = "addAddMethod()")
 private void checkSecurity() {
  System.out.println("Runned checkSecurity");
 }
}


An example interface(Target Object)
package com.gvace.inter;

public interface UserManager {
 public void addUser(String username,String password);
 public void delUser(int userId);
 public String findUserById(int userId);
 public void modifyUser(int userId, String username,String password);
}


The implementation of the interface(Target Object)

UserManagerImpl.java
package com.gvace.impl;

import com.gvace.inter.UserManager;

// each method have to call checkSecurity()
// and you don't want to change it based on requirement changes(like the codes being comment out)
public class UserManagerImpl implements UserManager {

 @Override
 public void addUser(String username, String password) {
  //checkSecurity();
  System.out.println("addUser:"+username+" "+password);
 }

 @Override
 public void delUser(int userId) {
  //checkSecurity();
  System.out.println("delUser:"+userId+" ");
 }

 @Override
 public String findUserById(int userId) {
  //checkSecurity();
  System.out.println("findUserById:"+userId+" ");
  return "findUserById"+userId;
 }

 @Override
 public void modifyUser(int userId, String username, String password) {
  //checkSecurity();
  System.out.println("modifyUser:"+userId+" "+username+" "+password);
 }
 /*
 public void checkSecurity(){
  System.out.println("Runned checkSecurity");
 }
 */
}


Register beans and aspect annotation

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/aop/spring-tx.xsd">

 <!-- Enable AspectJ Annotation -->
 <aop:aspectj-autoproxy/>
 
 <!-- Data Source -->
 <bean id="userManager" class="com.gvace.impl.UserManagerImpl"></bean>
 
 <!-- Aspect -->
 <bean id="securityHandler" class="com.gvace.aop.SecurityHandler"></bean>
</beans>


Test to run

Client.java
package com.gvace.test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gvace.inter.UserManager;

public class Client {
 public static void main(String[] args){
  BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserManager userManager = (UserManager)factory.getBean("userManager");
  //Since this UserManager interface contains function like execution(* add*(..))
  //this userManager reference will not be the implementation class, it will be a Proxy
  userManager.addUser("a", "b");
 }
}













Monday, April 25, 2016

Static Proxy and Dynamic Proxy

Normally like security check, transaction, log, these commonly used functions are not related to business logic, we can use proxy to separate these code from business codes

Think an interface has some functions
And before running each function in this interface, you need to call checkSecurity() first
To make the implementation cleaner
And which does not change when requirement for checkSecurity() changes
What solutions we have?

Example Interface:
package com.gvace.inter;

public interface UserManager {
 public void addUser(String username,String password);
 public void delUser(int userId);
 public String findUserById(int userId);
 public void modifyUser(int userId, String username,String password);
}

Clear Implementation example:
package com.gvace.impl;

import com.gvace.inter.UserManager;

// each method have to call checkSecurity()
// and you don't want to change it based on requirement changes(like the codes being comment out)
public class UserManagerImpl implements UserManager {

 @Override
 public void addUser(String username, String password) {
  //checkSecurity();
  System.out.println("addUser:"+username+" "+password);
 }

 @Override
 public void delUser(int userId) {
  //checkSecurity();
  System.out.println("delUser:"+userId+" ");
 }

 @Override
 public String findUserById(int userId) {
  //checkSecurity();
  System.out.println("findUserById:"+userId+" ");
  return "findUserById"+userId;
 }

 @Override
 public void modifyUser(int userId, String username, String password) {
  //checkSecurity();
  System.out.println("modifyUser:"+userId+" "+username+" "+password);
 }
 /*
 public void checkSecurity(){
  System.out.println("Runned checkSecurity");
 }
 */
}

Solution 1: Static Proxy
To simplify target implementation class, we build this proxy
We do checkSecurity() in proxy
So target implementation will not changed when requirement change
But we still have to call checkSecurity() in every method in this proxy
And we still have to change this proxy when requirement change

package com.gvace.proxy.static_;

import com.gvace.inter.UserManager;

/*
 * To simplify target implementation class, we build this proxy
 * We do checkSecurity() in proxy
 * So target implementation will not changed when requirement change
 * But we still have to call checkSecurity() in every method in this proxy
 * And we still have to change this proxy when requirement change
 * 
 * Thinking:
 * Actually checkSecurity() is separate logic from the target functions.
 * We need to find a way to separate it
 */
public class UserManagerImplProxy implements UserManager {
 UserManager userManager;
 public UserManagerImplProxy(UserManager userManager){
  this.userManager = userManager;
 }
 @Override
 public void addUser(String username, String password) {
  checkSecurity();
  userManager.addUser(username, password);
 }

 @Override
 public void delUser(int userId) {
  checkSecurity();
  userManager.delUser(userId);
 }

 @Override
 public String findUserById(int userId) {
  checkSecurity();
  return userManager.findUserById(userId);
 }

 @Override
 public void modifyUser(int userId, String username, String password) {
  checkSecurity();
  userManager.modifyUser(userId, username, password);
 }
 private void checkSecurity(){
  System.out.println("Runned checkSecurity");
 }
}


Thinking:
Actually checkSecurity() is separate logic from the target functions.
We need to find a way to separate it, so we have Solution 2



Solution 2: Dynamic Proxy

Create a Handler which implements InvocationHandler
This handler will register all functions from the target interfaces
So every-time the registered functions runs, it needs to go through the invoke() function in this handler
In this way, we can control the registered functions



package com.gvace.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


 //To use Dynamic Proxy
 //We build a InvocationHandler only for the function checkSecurity()


public class SecurityHandler implements InvocationHandler {
 private Object targetObject;

 public Object createProxyInstance(Object targetObject){
  //Save the targetObject as a reference
  this.targetObject = targetObject;
  
  
   // By creating this proxy
   // all interfaces' functions(targetObject.getClass().getInterfaces())
   // will be registered to this handler(filter) 
  return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
        targetObject.getClass().getInterfaces(),
        this);
 }

 
  // see java.lang.reflect.InvocationHandler
  // invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
  // 
  // invoke() like a filter of the target function
  // This will run every-time when the registered interfaces' functions runs
  

 @Override
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable {
  //do the checkSecurity()
  checkSecurity();
  
  //after checkSecurity() the filter is finished
  //we can invoke targetObject's function now.(like a filter chain)
  //or we can choose to return null, if it's not pass the checkSecurity() requirement
  return method.invoke(targetObject, args);
 }

 /*
  * checkSecurity() runs like invisible
  */
 private void checkSecurity() {
  System.out.println("Runned checkSecurity");
 }
}




And to run the target through this Handler
You can also use factory pattern to hide the procedure of creating handler and proxy instance

package com.gvace.test;

import com.gvace.impl.UserManagerImpl;
import com.gvace.inter.UserManager;
import com.gvace.proxy.dynamic.SecurityHandler;

public class Client {
 public static void main(String[] args){
  //Create a proxy instance
  //You can also hidden this by using a factory pattern
  SecurityHandler handler = new SecurityHandler();
  UserManager userManager = (UserManager)handler.createProxyInstance(new UserManagerImpl());
  
  userManager.addUser("aaa", "123");
 }
}

Static Proxy and Dynamic Proxy
Since dynamic proxy is dynamic registering the function, it's not efficient as static proxy.

Solution 3: Spring AOP
http://gvace.blogspot.com/2016/03/aop.html

Thursday, March 31, 2016

Spring AOP

AOP aspect oriented programming


Normally like security check, transaction, log, these commonly used functions are not related to business logic, we can use proxy to separate these code from business codes

Dynamic Proxy
AOP is done in theory of Dynamic Proxy
To understand how and why Dynamic Proxy works: 


Advice implements Aspect

Pointcut(add*): only apply on function name of add*


To see this Spring AOP with AspectJ with no Annotation Config(newer Version)
http://gvace.blogspot.com/2016/04/spring-aop-with-aspectj-no-annotation.html

To see Spring AOP with annotation(newer Version):
http://gvace.blogspot.com/2016/04/spring-aop-with-annotation.html

beans

Target Objects
Advice class
Proxy


Procedure
  1. define interface
  2. target bean class
  3. Advice class
  4. beans xml config
  5. config target bean
  6. config advice
  7. config proxy

Advice types
Advice typeInterfaceDescription
Aroundorg.aopalliance.intercept.MethodInterceptorIntercept target method
Beforeorg.springframework.aop.MethodBeforeAdviceCall before target method
Afterorg.springframework.aop.AfterReturningAdviceCall after target method returns
Throwsorg.springframework.aop.ThrowsAdviceCall when target method throws exception
Function Filter by Nameorg.springframework.aop.support.NameMatchMethodPointcutAdvisorApply only on function with the matched name



Advice order:
  1. MethodBeforeAdvice
  2. MethodInterceptor
  3. target method
  4. MethodInterceptor
  5. AfterReturningAdvice



ProxyFactoryBean:
Only need to setup, does not need code, use dynamic proxy instead
each ProxyFactoryBean only targets to one existed bean
  • proxyInterfaces: register interceptor on all functions of each interface
  • interceptorNames: register advice to run before/after all functions in proxyInterfaces
  • target: has to be only one existed bean


MethodInterceptor
Remember to get method return value, and return the value.

Example:
public class MyMethodInterceptor implements MethodInterceptor{
 
 /**
  * @methodInvocation
  * @return return what methodInvocation returns
  */
 @Override
 public Object invoke(MethodInvocation methodInvocation) throws Throwable {
  System.out.println("Before method invote "+methodInvocation.getMethod().getName());
  Object returnValue = methodInvocation.proceed();
  System.out.println("After method invote "+methodInvocation.getMethod().getName());
  return returnValue;
 }
 
}


ThrowsAdvice
Run when there is an error

ThrowsAdvice is just a flag, no function required to implement
Create either one of the following functions by yourself(See from example)
If created both, it always just run the one with multiple arguments


Example:
public class MyThrowsAdvice implements ThrowsAdvice{
 /*
  * ThrowsAdvice is just a flag, no function required to implement
  * Create either one of the following functions by yourself
  * 
  * If created both, it always just run the one with multiple arguments
  */
 public void afterThrowing(Throwable throwable){
  System.out.println("******Something WRONG!!!!!"+throwable.getMessage());
 }
 public void afterThrowing(Method m, Object[] os, Object target, Exception throwable){
  System.out.println("Something WRONG!!!!!"+throwable.getMessage());
 }
}



NameMatchMethodPointcutAdvisor
Like a Filter: apply only on function with the matched name(support regular expression)
Referenced on another Advice, and filter its function by matched name
So the referenced Advice does not need to register in the proxy, use this Filter instead
Just config, do not need implementation

Example:
<bean id="myMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
 <property name="advice" ref="MyMethodBeforeAdvice" />
 <property name="mappedNames">
  <list>
   <value>sayBye</value>
  </list>
 </property>
</bean>



Whole Process Example

  1. define interface
    public interface TestServiceInterface {
     public void sayHello();
    }
    public interface TestServiceInterface2 {
     public void sayBye();
    }
    
  2. target bean class
    public class Test1Service implements TestServiceInterface, TestServiceInterface2{
     private String name;
     public String getName() {
      return name;
     }
     public void setName(String name) {
      this.name = name;
     }
     @Override
     public void sayHello() {
      System.out.println("Hello "+name);
     }
     @Override
     public void sayBye() {
      System.out.println("Bye "+name);
     }
    
    }
    
  3. Advice class
    public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
     /**
      * @method target method
      * @args parameters of target method
      * @target target object
      */
     @Override
     public void before(Method method, Object[] args, Object target) 
       throws Throwable {  //method.invoke(target, args);
      System.out.println("Log"+method.getName());
     }
     
     
    }
    
  4. beans xml config
  5. config target bean
  6. config advice
  7. config proxy
  8. <!-- target objects -->
    <bean id="test1Service" class="com.gvace.aop.Test1Service">
     <property name="name" value="service1"></property>
    </bean>
    
    <!-- Method Before Advice -->
    <bean id="MyMethodBeforeAdvice" class="com.gvace.aop.MyMethodBeforeAdvice"></bean>
    
    <!-- Proxy Object -->
    <bean id="ProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
     <!-- config Target Object -->
     <property name="target" ref="test1Service" />
     <!-- Proxy Interface collection -->
     <property name="proxyInterfaces">
      <list>
       <value>com.gvace.aop.TestServiceInterface</value>
       <value>com.gvace.aop.TestServiceInterface2</value>
      </list>
     </property>
     <!-- Insert Advice into proxy object -->
     <property name="interceptorNames">
      <!-- link Advices with ProxyFactoryBean -->
      <list>
       <value>MyMethodBeforeAdvice</value>
      </list>
     </property>
    </bean>