Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Tuesday, August 2, 2016

Reference Type Strong/Soft/Weak/Phantom

Strong
Regular reference

Soft
Used for memory cache, only gc when memory not enough

Weak
Used for storing data, only gc on the second time. Example: ClassLoader

Phantom
Used only for monitoring if object has already been gc

Reference Queue
When an object has been gc, we can poll it from ReferenceQueue


import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class ReferenceType {
 public static void main(String[] args) throws InterruptedException{
  String s1 = new String("aaa");
  String s2 = new String("bbb");
  String s3 = new String("ccc");
  
  ReferenceQueue<String> srq = new ReferenceQueue<String>();
  SoftReference<String> ss = new SoftReference<String>(s1,srq);
  ReferenceQueue<String> wrq = new ReferenceQueue<String>();
  WeakReference<String> ws = new WeakReference<String>(s2,wrq);
  ReferenceQueue<String> prq = new ReferenceQueue<String>();
  PhantomReference<String> ps = new PhantomReference<String>(s3,prq);
  
  s1 = null;
  s2 = null;
  s3 = null;
  
  System.gc();
    
  System.out.println("ss="+ss.get());
  System.out.println("srq="+srq.poll());
  System.out.println("ws="+ws.get());
  System.out.println("wrq="+wrq.poll());
  System.out.println("ps="+ps.get());
  System.out.println("prq="+prq.poll());
 }
}


Output result
ss=aaa
srq=null
ws=null
wrq=java.lang.ref.WeakReference@15db9742
ps=null
prq=java.lang.ref.PhantomReference@6d06d69c




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

Sunday, January 24, 2016

Full Example of declare and use an annotation

To see the basic concept of Annotation: here
To see the basic concept of declare an Annotation: here

Goal:
Declare table and field annotation for SQL database, so when we can build ORM(Object Relationship Mapping)

SQLTable Annotation:
@Target(value=ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLTable {
 String value(); //table name
}

SQLField Annotation:
@Target(value=ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLField {
 String column();
 String type();
 int length();
}
Table structure

A Model class using annotations as description
@SQLTable("student")
public class Student {
 @SQLField(column="id",type="int",length=10)
 private int id;
 @SQLField(column="name",type="varchar",length=10)
 private String studentName;
 @SQLField(column="age",type="int",length=3)
 private int age;
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getStudentName() {
  return studentName;
 }
 public void setStudentName(String studentName) {
  this.studentName = studentName;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 
}


Use Annotation to build SQL:


public class Demo2 {
 @Test
 public void test(){
  try{
   Class clazz = Class.forName("model.Student");
   
   //(1)get all annotations for the class
   Annotation[] annotations = clazz.getAnnotations();
   for(Annotation a: annotations){
    System.out.println(a);
   }
   //(1) get the specified annotation for the class
   SQLTable table = (SQLTable) clazz.getAnnotation(SQLTable.class);
   System.out.println(table);
   
   //(2) get annotation for the field
   Field f = clazz.getDeclaredField("studentName"); //get the target field from class
   SQLField myField = f.getAnnotation(SQLField.class); //get the annotation for this field
   //use function declared in annotation
   System.out.println(myField.column()+","+myField.type()+","+myField.length());  
   
   //based on (1) and (2), we can build up all info for the related sql table   
   
  }catch(Exception e){
   
  }
 }
}

Declare Annotation

When using @interface to declare an annotation, it inherited  java.lang.annotation.Annotation interface.


  • @interface is used to declare an annotation
    format:   public @interface AnnotationName{//body}
  • Each method inside the body declares a config parameter
  1. function name is parameter name
  2. return type is parameter type(return type can only be primitive, Class, String, enum)
  3. can use "default" to declare parameter default value
  4. if there is only one parameter, normally it's name is "value"
  5. Normally we use "", or 0 to be default value, we also use -1 to assign the meaning of not exist.
  6. When using annotation, if there is only one parameter, we don't have to specify parameter name
There are four primitive Annotation
  1. @Target
  2. @Retention
  3. @Documented
  4. @Inherited
1. @Target
     Specify the annotation apply target, can be package, class, method, variables etc.

2. @Retention
    Specify when it can be applied, either source(.java) file, (.class) file, or in runtime

Declare Annotation Example

//@Target(value=ElementType.METHOD)
@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation01 {
 String studentName() default "";
 int age() default 0;
 int id() default -1;
 String[] schools() default {};
}


Using Annotation Example
@CustomAnnotation01(schools = { "" })
public class Demo1 {
 @CustomAnnotation01(studentName="AAA",age=0,id=1001,schools={"aaa","bbb"})
 public void test(){
  
 }
}

To see the basic concept of Annotation: here
To see the full example of how to declare and use annotation: here

Annotation

Reference from oracle tutorial

Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.
Annotations have a number of uses, among them:
  • Information for the compiler — Annotations can be used by the compiler to detect errors or suppress warnings.
  • Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth.
  • Runtime processing — Some annotations are available to be examined at runtime.

Used on

  • package
  • class
  • method
  • field

@Override  //mark as override function from super classes
public String toString(){
}

Take a look at declaration

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}


@Deprecated   //out of date, not suggested use
Take a look at declaration

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}


@SuppressWarnings  //ignore warning when compile
public static void test(){
List list = new ArrayList();
}

Take a look at declaration

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is not an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * Compiler vendors should document the warning names they support in
     * conjunction with this annotation type. They are encouraged to cooperate
     * to ensure that the same names work across multiple compilers.
     */
    String[] value();
}

See usage of Annotation:
Declare Annotation