Java 根据spring中的字符串参数调用不同的服务

Java 根据spring中的字符串参数调用不同的服务,java,spring-boot,Java,Spring Boot,在我的控制器中,我接收到一个字符串参数,根据该参数我需要决定调用哪个服务,如何在使用Spring注释的Spring引导应用程序中执行相同的操作 例如:我们有不同类型的汽车。现在,根据请求中的参数,我应该能够决定应该调用哪个特定的汽车服务 如何在Spring Boot中创建一个使用注释的工厂,并且应该根据输入从该工厂返回对象。我记得几年前实现了对这种方法的支持,我相信,作为我的实用程序库的入口点,请在方便时使用以下代码片段: Strategy.java package ... @Document

在我的控制器中,我接收到一个字符串参数,根据该参数我需要决定调用哪个服务,如何在使用Spring注释的Spring引导应用程序中执行相同的操作

例如:我们有不同类型的汽车。现在,根据请求中的参数,我应该能够决定应该调用哪个特定的汽车服务


如何在Spring Boot中创建一个使用注释的工厂,并且应该根据输入从该工厂返回对象。

我记得几年前实现了对这种方法的支持,我相信,作为我的实用程序库的入口点,请在方便时使用以下代码片段:

Strategy.java

package ...

@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {

    Class<?> type();

    String[] profiles() default {};
}
package ...

public class StrategyFactory {

    private static final Logger LOG = Logger.getLogger( StrategyFactory.class );

    private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();

    private String[] packages;

    @PostConstruct
    public void init() {
        if (this.packages != null) {
            Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
            for (String pack : this.packages) {
                Reflections reflections = new Reflections( pack );
                annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
            }
            this.sanityCheck( annotatedClasses );
        }
    }

    public <T> T getStrategy(Class<T> strategyClass) {
        return this.getStrategy( strategyClass, null );
    }

    @SuppressWarnings("unchecked")
    public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
        Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
        if (clazz == null) {
            throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with @Strategy?", strategyClass.getName() ) );
        }
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.rethrowAs( e, StrategyException.class );
        }
    }

    /**
     * Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
     * @param annotatedClasses a list of classes
     */
    private void sanityCheck(Set<Class<?>> annotatedClasses) {
        Set<String> usedStrategies = new HashSet<String>();
        for (Class<?> annotatedClass : annotatedClasses) {
            Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
            if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
                throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
            }
            this.strategiesCache.put( annotatedClass, strategyAnnotation );

            if (this.isDefault( strategyAnnotation )) {
                this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
            } else {
                for (String profile : strategyAnnotation.profiles()) {
                    this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
                }
            }
        }
    }

    private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
        String key = this.createKey( type, profile );
        if (usedStrategies.contains( key )) {
            throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
        }
        usedStrategies.add( key );
    }

    private String createKey(Class<?> type, String profile) {
        return String.format( "%s_%s", type, profile ).toLowerCase();
    }

    private boolean isDefault(Strategy strategyAnnotation) {
        return (strategyAnnotation.profiles().length == 0);
    }

    private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
        for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
            Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
            if (strategyCacheEntryValue.type().equals( strategyClass )) {
                if (currentProfile != null) {
                    for (String profile : strategyCacheEntryValue.profiles()) {
                        if (currentProfile.equals( profile )) {
                            Class<?> result = strategyCacheEntry.getKey();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
                            }
                            return result;
                        }
                    }
                } else if (this.isDefault( strategyCacheEntryValue )) {
                    Class<?> defaultClass = strategyCacheEntry.getKey();
                    if (LOG.isDebugEnabled()) {
                        LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
                    }
                    return defaultClass;
                }
            }
        }
        return null;
    }

    public void setPackages(String[] packages) {
        this.packages = packages;
    }
}
package ...

public class StrategyException extends RuntimeException {
...
}
package ...

public class StrategyNotFoundException extends StrategyException {
...
}
package ...

public class StrategyProfileViolationException extends StrategyException {
...
}
package com.asimio.core.test.strategy.strategies.navigation;

public interface NavigationStrategy {

    public String naviateTo();
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "free";
    }
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "limited+premium";
    }
}
package ...

public interface IFeedProcessor {

    void runBatch(String file);
}
package ...

@Configurable(dependencyCheck = true)
@Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {

    @Autowired
    private CsvRentalsBatchReporter batchReporter;
...
}
StrategyNotFoundException.java

package ...

@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {

    Class<?> type();

    String[] profiles() default {};
}
package ...

public class StrategyFactory {

    private static final Logger LOG = Logger.getLogger( StrategyFactory.class );

    private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();

    private String[] packages;

    @PostConstruct
    public void init() {
        if (this.packages != null) {
            Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
            for (String pack : this.packages) {
                Reflections reflections = new Reflections( pack );
                annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
            }
            this.sanityCheck( annotatedClasses );
        }
    }

    public <T> T getStrategy(Class<T> strategyClass) {
        return this.getStrategy( strategyClass, null );
    }

    @SuppressWarnings("unchecked")
    public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
        Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
        if (clazz == null) {
            throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with @Strategy?", strategyClass.getName() ) );
        }
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.rethrowAs( e, StrategyException.class );
        }
    }

    /**
     * Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
     * @param annotatedClasses a list of classes
     */
    private void sanityCheck(Set<Class<?>> annotatedClasses) {
        Set<String> usedStrategies = new HashSet<String>();
        for (Class<?> annotatedClass : annotatedClasses) {
            Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
            if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
                throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
            }
            this.strategiesCache.put( annotatedClass, strategyAnnotation );

            if (this.isDefault( strategyAnnotation )) {
                this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
            } else {
                for (String profile : strategyAnnotation.profiles()) {
                    this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
                }
            }
        }
    }

    private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
        String key = this.createKey( type, profile );
        if (usedStrategies.contains( key )) {
            throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
        }
        usedStrategies.add( key );
    }

    private String createKey(Class<?> type, String profile) {
        return String.format( "%s_%s", type, profile ).toLowerCase();
    }

    private boolean isDefault(Strategy strategyAnnotation) {
        return (strategyAnnotation.profiles().length == 0);
    }

    private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
        for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
            Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
            if (strategyCacheEntryValue.type().equals( strategyClass )) {
                if (currentProfile != null) {
                    for (String profile : strategyCacheEntryValue.profiles()) {
                        if (currentProfile.equals( profile )) {
                            Class<?> result = strategyCacheEntry.getKey();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
                            }
                            return result;
                        }
                    }
                } else if (this.isDefault( strategyCacheEntryValue )) {
                    Class<?> defaultClass = strategyCacheEntry.getKey();
                    if (LOG.isDebugEnabled()) {
                        LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
                    }
                    return defaultClass;
                }
            }
        }
        return null;
    }

    public void setPackages(String[] packages) {
        this.packages = packages;
    }
}
package ...

public class StrategyException extends RuntimeException {
...
}
package ...

public class StrategyNotFoundException extends StrategyException {
...
}
package ...

public class StrategyProfileViolationException extends StrategyException {
...
}
package com.asimio.core.test.strategy.strategies.navigation;

public interface NavigationStrategy {

    public String naviateTo();
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "free";
    }
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "limited+premium";
    }
}
package ...

public interface IFeedProcessor {

    void runBatch(String file);
}
package ...

@Configurable(dependencyCheck = true)
@Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {

    @Autowired
    private CsvRentalsBatchReporter batchReporter;
...
}
StrategyProfileViolationException.java

package ...

@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {

    Class<?> type();

    String[] profiles() default {};
}
package ...

public class StrategyFactory {

    private static final Logger LOG = Logger.getLogger( StrategyFactory.class );

    private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();

    private String[] packages;

    @PostConstruct
    public void init() {
        if (this.packages != null) {
            Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
            for (String pack : this.packages) {
                Reflections reflections = new Reflections( pack );
                annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
            }
            this.sanityCheck( annotatedClasses );
        }
    }

    public <T> T getStrategy(Class<T> strategyClass) {
        return this.getStrategy( strategyClass, null );
    }

    @SuppressWarnings("unchecked")
    public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
        Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
        if (clazz == null) {
            throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with @Strategy?", strategyClass.getName() ) );
        }
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.rethrowAs( e, StrategyException.class );
        }
    }

    /**
     * Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
     * @param annotatedClasses a list of classes
     */
    private void sanityCheck(Set<Class<?>> annotatedClasses) {
        Set<String> usedStrategies = new HashSet<String>();
        for (Class<?> annotatedClass : annotatedClasses) {
            Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
            if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
                throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
            }
            this.strategiesCache.put( annotatedClass, strategyAnnotation );

            if (this.isDefault( strategyAnnotation )) {
                this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
            } else {
                for (String profile : strategyAnnotation.profiles()) {
                    this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
                }
            }
        }
    }

    private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
        String key = this.createKey( type, profile );
        if (usedStrategies.contains( key )) {
            throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
        }
        usedStrategies.add( key );
    }

    private String createKey(Class<?> type, String profile) {
        return String.format( "%s_%s", type, profile ).toLowerCase();
    }

    private boolean isDefault(Strategy strategyAnnotation) {
        return (strategyAnnotation.profiles().length == 0);
    }

    private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
        for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
            Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
            if (strategyCacheEntryValue.type().equals( strategyClass )) {
                if (currentProfile != null) {
                    for (String profile : strategyCacheEntryValue.profiles()) {
                        if (currentProfile.equals( profile )) {
                            Class<?> result = strategyCacheEntry.getKey();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
                            }
                            return result;
                        }
                    }
                } else if (this.isDefault( strategyCacheEntryValue )) {
                    Class<?> defaultClass = strategyCacheEntry.getKey();
                    if (LOG.isDebugEnabled()) {
                        LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
                    }
                    return defaultClass;
                }
            }
        }
        return null;
    }

    public void setPackages(String[] packages) {
        this.packages = packages;
    }
}
package ...

public class StrategyException extends RuntimeException {
...
}
package ...

public class StrategyNotFoundException extends StrategyException {
...
}
package ...

public class StrategyProfileViolationException extends StrategyException {
...
}
package com.asimio.core.test.strategy.strategies.navigation;

public interface NavigationStrategy {

    public String naviateTo();
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "free";
    }
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "limited+premium";
    }
}
package ...

public interface IFeedProcessor {

    void runBatch(String file);
}
package ...

@Configurable(dependencyCheck = true)
@Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {

    @Autowired
    private CsvRentalsBatchReporter batchReporter;
...
}
不带弹簧的使用方法

<bean id="strategyFactory" class="com.asimio.core.strategy.StrategyFactory">
    <property name="packages">
        <list>
            <value>com.asimio.jobs.feed.impl</value>
        </list>
    </property>
</bean>
NavigationStrategy.java

package ...

@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {

    Class<?> type();

    String[] profiles() default {};
}
package ...

public class StrategyFactory {

    private static final Logger LOG = Logger.getLogger( StrategyFactory.class );

    private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();

    private String[] packages;

    @PostConstruct
    public void init() {
        if (this.packages != null) {
            Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
            for (String pack : this.packages) {
                Reflections reflections = new Reflections( pack );
                annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
            }
            this.sanityCheck( annotatedClasses );
        }
    }

    public <T> T getStrategy(Class<T> strategyClass) {
        return this.getStrategy( strategyClass, null );
    }

    @SuppressWarnings("unchecked")
    public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
        Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
        if (clazz == null) {
            throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with @Strategy?", strategyClass.getName() ) );
        }
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.rethrowAs( e, StrategyException.class );
        }
    }

    /**
     * Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
     * @param annotatedClasses a list of classes
     */
    private void sanityCheck(Set<Class<?>> annotatedClasses) {
        Set<String> usedStrategies = new HashSet<String>();
        for (Class<?> annotatedClass : annotatedClasses) {
            Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
            if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
                throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
            }
            this.strategiesCache.put( annotatedClass, strategyAnnotation );

            if (this.isDefault( strategyAnnotation )) {
                this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
            } else {
                for (String profile : strategyAnnotation.profiles()) {
                    this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
                }
            }
        }
    }

    private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
        String key = this.createKey( type, profile );
        if (usedStrategies.contains( key )) {
            throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
        }
        usedStrategies.add( key );
    }

    private String createKey(Class<?> type, String profile) {
        return String.format( "%s_%s", type, profile ).toLowerCase();
    }

    private boolean isDefault(Strategy strategyAnnotation) {
        return (strategyAnnotation.profiles().length == 0);
    }

    private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
        for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
            Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
            if (strategyCacheEntryValue.type().equals( strategyClass )) {
                if (currentProfile != null) {
                    for (String profile : strategyCacheEntryValue.profiles()) {
                        if (currentProfile.equals( profile )) {
                            Class<?> result = strategyCacheEntry.getKey();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
                            }
                            return result;
                        }
                    }
                } else if (this.isDefault( strategyCacheEntryValue )) {
                    Class<?> defaultClass = strategyCacheEntry.getKey();
                    if (LOG.isDebugEnabled()) {
                        LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
                    }
                    return defaultClass;
                }
            }
        }
        return null;
    }

    public void setPackages(String[] packages) {
        this.packages = packages;
    }
}
package ...

public class StrategyException extends RuntimeException {
...
}
package ...

public class StrategyNotFoundException extends StrategyException {
...
}
package ...

public class StrategyProfileViolationException extends StrategyException {
...
}
package com.asimio.core.test.strategy.strategies.navigation;

public interface NavigationStrategy {

    public String naviateTo();
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "free";
    }
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "limited+premium";
    }
}
package ...

public interface IFeedProcessor {

    void runBatch(String file);
}
package ...

@Configurable(dependencyCheck = true)
@Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {

    @Autowired
    private CsvRentalsBatchReporter batchReporter;
...
}
FreeNavigationStrategy.java

package ...

@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {

    Class<?> type();

    String[] profiles() default {};
}
package ...

public class StrategyFactory {

    private static final Logger LOG = Logger.getLogger( StrategyFactory.class );

    private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();

    private String[] packages;

    @PostConstruct
    public void init() {
        if (this.packages != null) {
            Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
            for (String pack : this.packages) {
                Reflections reflections = new Reflections( pack );
                annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
            }
            this.sanityCheck( annotatedClasses );
        }
    }

    public <T> T getStrategy(Class<T> strategyClass) {
        return this.getStrategy( strategyClass, null );
    }

    @SuppressWarnings("unchecked")
    public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
        Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
        if (clazz == null) {
            throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with @Strategy?", strategyClass.getName() ) );
        }
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.rethrowAs( e, StrategyException.class );
        }
    }

    /**
     * Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
     * @param annotatedClasses a list of classes
     */
    private void sanityCheck(Set<Class<?>> annotatedClasses) {
        Set<String> usedStrategies = new HashSet<String>();
        for (Class<?> annotatedClass : annotatedClasses) {
            Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
            if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
                throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
            }
            this.strategiesCache.put( annotatedClass, strategyAnnotation );

            if (this.isDefault( strategyAnnotation )) {
                this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
            } else {
                for (String profile : strategyAnnotation.profiles()) {
                    this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
                }
            }
        }
    }

    private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
        String key = this.createKey( type, profile );
        if (usedStrategies.contains( key )) {
            throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
        }
        usedStrategies.add( key );
    }

    private String createKey(Class<?> type, String profile) {
        return String.format( "%s_%s", type, profile ).toLowerCase();
    }

    private boolean isDefault(Strategy strategyAnnotation) {
        return (strategyAnnotation.profiles().length == 0);
    }

    private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
        for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
            Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
            if (strategyCacheEntryValue.type().equals( strategyClass )) {
                if (currentProfile != null) {
                    for (String profile : strategyCacheEntryValue.profiles()) {
                        if (currentProfile.equals( profile )) {
                            Class<?> result = strategyCacheEntry.getKey();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
                            }
                            return result;
                        }
                    }
                } else if (this.isDefault( strategyCacheEntryValue )) {
                    Class<?> defaultClass = strategyCacheEntry.getKey();
                    if (LOG.isDebugEnabled()) {
                        LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
                    }
                    return defaultClass;
                }
            }
        }
        return null;
    }

    public void setPackages(String[] packages) {
        this.packages = packages;
    }
}
package ...

public class StrategyException extends RuntimeException {
...
}
package ...

public class StrategyNotFoundException extends StrategyException {
...
}
package ...

public class StrategyProfileViolationException extends StrategyException {
...
}
package com.asimio.core.test.strategy.strategies.navigation;

public interface NavigationStrategy {

    public String naviateTo();
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "free";
    }
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "limited+premium";
    }
}
package ...

public interface IFeedProcessor {

    void runBatch(String file);
}
package ...

@Configurable(dependencyCheck = true)
@Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {

    @Autowired
    private CsvRentalsBatchReporter batchReporter;
...
}
LimitedPremiumNavigationStrategy.java

package ...

@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {

    Class<?> type();

    String[] profiles() default {};
}
package ...

public class StrategyFactory {

    private static final Logger LOG = Logger.getLogger( StrategyFactory.class );

    private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();

    private String[] packages;

    @PostConstruct
    public void init() {
        if (this.packages != null) {
            Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
            for (String pack : this.packages) {
                Reflections reflections = new Reflections( pack );
                annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
            }
            this.sanityCheck( annotatedClasses );
        }
    }

    public <T> T getStrategy(Class<T> strategyClass) {
        return this.getStrategy( strategyClass, null );
    }

    @SuppressWarnings("unchecked")
    public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
        Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
        if (clazz == null) {
            throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with @Strategy?", strategyClass.getName() ) );
        }
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.rethrowAs( e, StrategyException.class );
        }
    }

    /**
     * Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
     * @param annotatedClasses a list of classes
     */
    private void sanityCheck(Set<Class<?>> annotatedClasses) {
        Set<String> usedStrategies = new HashSet<String>();
        for (Class<?> annotatedClass : annotatedClasses) {
            Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
            if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
                throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
            }
            this.strategiesCache.put( annotatedClass, strategyAnnotation );

            if (this.isDefault( strategyAnnotation )) {
                this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
            } else {
                for (String profile : strategyAnnotation.profiles()) {
                    this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
                }
            }
        }
    }

    private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
        String key = this.createKey( type, profile );
        if (usedStrategies.contains( key )) {
            throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
        }
        usedStrategies.add( key );
    }

    private String createKey(Class<?> type, String profile) {
        return String.format( "%s_%s", type, profile ).toLowerCase();
    }

    private boolean isDefault(Strategy strategyAnnotation) {
        return (strategyAnnotation.profiles().length == 0);
    }

    private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
        for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
            Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
            if (strategyCacheEntryValue.type().equals( strategyClass )) {
                if (currentProfile != null) {
                    for (String profile : strategyCacheEntryValue.profiles()) {
                        if (currentProfile.equals( profile )) {
                            Class<?> result = strategyCacheEntry.getKey();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
                            }
                            return result;
                        }
                    }
                } else if (this.isDefault( strategyCacheEntryValue )) {
                    Class<?> defaultClass = strategyCacheEntry.getKey();
                    if (LOG.isDebugEnabled()) {
                        LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
                    }
                    return defaultClass;
                }
            }
        }
        return null;
    }

    public void setPackages(String[] packages) {
        this.packages = packages;
    }
}
package ...

public class StrategyException extends RuntimeException {
...
}
package ...

public class StrategyNotFoundException extends StrategyException {
...
}
package ...

public class StrategyProfileViolationException extends StrategyException {
...
}
package com.asimio.core.test.strategy.strategies.navigation;

public interface NavigationStrategy {

    public String naviateTo();
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "free";
    }
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "limited+premium";
    }
}
package ...

public interface IFeedProcessor {

    void runBatch(String file);
}
package ...

@Configurable(dependencyCheck = true)
@Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {

    @Autowired
    private CsvRentalsBatchReporter batchReporter;
...
}
然后

使用弹簧时

<bean id="strategyFactory" class="com.asimio.core.strategy.StrategyFactory">
    <property name="packages">
        <list>
            <value>com.asimio.jobs.feed.impl</value>
        </list>
    </property>
</bean>
Spring上下文文件

<bean id="strategyFactory" class="com.asimio.core.strategy.StrategyFactory">
    <property name="packages">
        <list>
            <value>com.asimio.jobs.feed.impl</value>
        </list>
    </property>
</bean>
CsvRentalsFeedProcessor.java

package ...

@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {

    Class<?> type();

    String[] profiles() default {};
}
package ...

public class StrategyFactory {

    private static final Logger LOG = Logger.getLogger( StrategyFactory.class );

    private Map<Class<?>, Strategy> strategiesCache = new HashMap<Class<?>, Strategy>();

    private String[] packages;

    @PostConstruct
    public void init() {
        if (this.packages != null) {
            Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
            for (String pack : this.packages) {
                Reflections reflections = new Reflections( pack );
                annotatedClasses.addAll( reflections.getTypesAnnotatedWith( Strategy.class ) );
            }
            this.sanityCheck( annotatedClasses );
        }
    }

    public <T> T getStrategy(Class<T> strategyClass) {
        return this.getStrategy( strategyClass, null );
    }

    @SuppressWarnings("unchecked")
    public <T> T getStrategy(Class<T> strategyClass, String currentProfile) {
        Class<T> clazz = (Class<T>) this.findStrategyMatchingProfile( strategyClass, currentProfile );
        if (clazz == null) {
            throw new StrategyNotFoundException( String.format( "No strategies found of type '%s', are the strategies marked with @Strategy?", strategyClass.getName() ) );
        }
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            throw ExceptionUtils.rethrowAs( e, StrategyException.class );
        }
    }

    /**
     * Checks to make sure there is only one strategy of each type(Interface) annotated for each profile Will throw an exception on startup if multiple strategies are mapped to the same profile.
     * @param annotatedClasses a list of classes
     */
    private void sanityCheck(Set<Class<?>> annotatedClasses) {
        Set<String> usedStrategies = new HashSet<String>();
        for (Class<?> annotatedClass : annotatedClasses) {
            Strategy strategyAnnotation = AnnotationUtils.findAnnotation( annotatedClass, Strategy.class );
            if (!strategyAnnotation.type().isAssignableFrom( annotatedClass )) {
                throw new StrategyProfileViolationException( String.format( "'%s' should be assignable from '%s'", strategyAnnotation.type(), annotatedClass ) );
            }
            this.strategiesCache.put( annotatedClass, strategyAnnotation );

            if (this.isDefault( strategyAnnotation )) {
                this.ifNotExistAdd( strategyAnnotation.type(), "default", usedStrategies );
            } else {
                for (String profile : strategyAnnotation.profiles()) {
                    this.ifNotExistAdd( strategyAnnotation.type(), profile, usedStrategies );
                }
            }
        }
    }

    private void ifNotExistAdd(Class<?> type, String profile, Set<String> usedStrategies) {
        String key = this.createKey( type, profile );
        if (usedStrategies.contains( key )) {
            throw new StrategyProfileViolationException( String.format( "There can only be a single strategy for each type, found multiple for type '%s' and profile '%s'", type, profile ) );
        }
        usedStrategies.add( key );
    }

    private String createKey(Class<?> type, String profile) {
        return String.format( "%s_%s", type, profile ).toLowerCase();
    }

    private boolean isDefault(Strategy strategyAnnotation) {
        return (strategyAnnotation.profiles().length == 0);
    }

    private Class<?> findStrategyMatchingProfile(Class<?> strategyClass, String currentProfile) {
        for (Map.Entry<Class<?>, Strategy> strategyCacheEntry : this.strategiesCache.entrySet()) {
            Strategy strategyCacheEntryValue = strategyCacheEntry.getValue();
            if (strategyCacheEntryValue.type().equals( strategyClass )) {
                if (currentProfile != null) {
                    for (String profile : strategyCacheEntryValue.profiles()) {
                        if (currentProfile.equals( profile )) {
                            Class<?> result = strategyCacheEntry.getKey();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug( String.format( "Found strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, result ) );
                            }
                            return result;
                        }
                    }
                } else if (this.isDefault( strategyCacheEntryValue )) {
                    Class<?> defaultClass = strategyCacheEntry.getKey();
                    if (LOG.isDebugEnabled()) {
                        LOG.debug( String.format( "Found default strategy [strategy=%s, profile=%s, strategyImpl=%s]", strategyClass, currentProfile, defaultClass ) );
                    }
                    return defaultClass;
                }
            }
        }
        return null;
    }

    public void setPackages(String[] packages) {
        this.packages = packages;
    }
}
package ...

public class StrategyException extends RuntimeException {
...
}
package ...

public class StrategyNotFoundException extends StrategyException {
...
}
package ...

public class StrategyProfileViolationException extends StrategyException {
...
}
package com.asimio.core.test.strategy.strategies.navigation;

public interface NavigationStrategy {

    public String naviateTo();
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class)
public class FreeNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "free";
    }
}
package com.asimio.core.test.strategy.strategies.navigation;

@Strategy(type = NavigationStrategy.class, profiles = { "limited", "premium" })
public class LimitedPremiumNavigationStrategy implements NavigationStrategy {

    public String naviateTo() {
        return "limited+premium";
    }
}
package ...

public interface IFeedProcessor {

    void runBatch(String file);
}
package ...

@Configurable(dependencyCheck = true)
@Strategy(type = IFeedProcessor.class, profiles = { "csv" })
public class CsvRentalsFeedProcessor implements IFeedProcessor, Serializable {

    @Autowired
    private CsvRentalsBatchReporter batchReporter;
...
}
然后

注意
CsvRentalsFeedProcessor
bean(策略实现)中的
CsvRentalsBatchReporter
被“注入”,但
StrategyFactory
使用
return(T)clazz.newInstance()实例化策略实现,那么需要什么使这个对象
Spring
-感知呢?
首先用
@Configurable(dependencyCheck=true)
注释
CsvRentalsFeedProcessor
,运行Java应用程序时,Java命令中需要此参数:
-javaagent:

您尝试了什么?你面临的具体问题是什么?这个问题是在一次采访中向我提出的,现在我想实际实现它以扩大我在这个主题上的知识。我想在spring中使用注释实现一个工厂,通常我们使用serviceLocator接口来实现工厂(使用xml),但是如何通过使用注释来实现同样的效果这比需要的要复杂得多。只要让所有strategy Spring bean实现一个strategy接口,在您的工厂中自动生成一个列表,确保每个strategy bean返回它允许管理的汽车类型,就可以了。策略是SpringBean,因此受益于依赖注入、AOP等。我明白你的意思,但是Strategy注释、StrategyFactory和异常类可以在spring和非spring环境中使用注释以一种非常干净和有趣的方式打包和重用,顺便说一句,Asish提出了这个问题,“我怎样才能拥有一个使用注释的工厂。。。“@ootero-据我所知,您使用反射从名称创建bean,这就是我们在java中可以根据传递的字符串返回对象的方法,当面试官问我时,我也回答说我们可以使用反射,只是您提供了一个非常好的实现(带有反射和策略设计模式)…但我在寻找没有反射的东西……比如带有注释的服务定位器的实现