660 likes | 811 Views
Introduction to Spring.NET. Speaker’s Qualifications. Mark Pollack is a founding partner at CodeStreet LLC, a software and consulting firm in the financial services industry.
E N D
Introduction to Spring.NET
Speaker’s Qualifications • Mark Pollack is a founding partner at CodeStreet LLC, a software and consulting firm in the financial services industry. • .NET and J2EE architect and developer specializing in financial front office solutions, EAI, and message based middleware • Spring Developer (2003) • JmsTemplate, Annotation abstraction • Contributing author • Java Development with the Spring Framework • JMS Section • Founder and Co-lead of Spring.NET (2004) • Speaker at various Spring related conferences
Outline • Why a .NET version? • Introduction to IoC/AOP • Core Spring.NET Technologies • IoC Container • AOP • Additional functionality packaged in Spring.Core • Services • Remoting, WebServices, EnterpriseServices Middle Tier Data Access • Web • Data Access • Additional Modules • NHibernate, TIBCO, Threading.Concurrent
Why Spring.NET? • There is always a need for a good application framework, regardless of the platform • Makes life easier to companies and developers using both platforms • We got spoiled by Spring and wanted to be able to build .NET apps in a similar way • The programming model, ideas and architectural concepts in Spring are not platform specific • Are GoF design patterns platform specific? • “It is as much a collection of best practices as it is a framework.”
Spring.NET Project Overview • Not a blind port of Spring • .NET developers feel ‘right at home’ • Spring.Java developers feel ‘right at home’ • Version 1.0 released September 2005 • 1.0.3/1.1 RC1 October 2006 (Web + Services)
Spring.NET Project Overview • Documentation • ~200 pages reference • API documentation • VS.NET integration • “Quick Start” examples with documentation • Unit tests with high % code coverage • Continuous Integration • ~2,600 downloads/month • More from nightly builds • MSI Installer • User Forums • JIRA issue Tracking • Fisheye Repository Browser
Spring’s “Nature” • Layered Framework • Control flow driven by core container • Can be a one stop shop or just use certain subsystems • Separation between the modules is ‘enforced’. • Can also be considered a library • Implementation classes are considered as a public API • ContextRegistry, ProxyFactory, Template classes • Not an all-or-nothing solution
Desktop Web AOP Services Data Access Core Spring.NET Modules • Main Platform • Separate Module Projects Windows Services NHibernate TIBCO
Spring in relation to the J2EE/.NET stack • Spring is broad but not deep • Address end-to-end requirements rather than one tier • Consistent programming model across different technologies within the stack • Expands on base APIs/technologies that are deep. • Analogy with an ice flow
Spring in relation to the J2EE/.NET stack • J2EE/.NET stack is deep. How much code to implement the following • Distributed Transaction Manager • Messaging Server • Web Server • etc… • Analogy with an iceberg • See a small narrow view of a big foundation; the public APIs, above the waterline
Approaches to application configuration • Flow of control in a “traditional” application as it relates to obtaining other objects and services • ‘Your’ code calls out to class libraries and creates other objects and services as necessary. • You ‘new’ and configure the objects. • If using interfaces typically create many specialized factory classes. • Factory classes may or may not configure returned object. • Inversion of Control presents an alternative approach
Scenario • Simplified “PortfolioManager” • Calculate value of portfolio • Obtain collection of instruments by Account ID • Compute the present value of each instrument public class PortfolioManager { public void CalculatePresentValue(string accountId) { Portfolio portfolio = GetPortfolioFromTradingSystems(accountId); foreach (Position position in portfolio.Positions) { double baseValue = PriceInstrument(position.Instrument); position.PositionValue = position.QuantityHeld * baseValue; portfolio.PresentValue += position.PositionValue; } } /// other methods . . . }
“Traditional” Implementation • Use of interfaces private Portfolio GetPortfolioFromTradingSystems(string accountId) { ITradingService s = TradingServiceFactory.CreateTradingService(); IList positions = s.GetPositions(accountId); Portfolio p = new Portfolio("Porfolio for account " + accountId); p.Positions.Add(positions); return p; } public double PriceInstrument(Instrument i) { IPricingService p = PricingServiceFactory.CreatePricingService(); return p.PriceInstrument(i); }
PricingServiceFactory Implementation public class PricingServiceFactory { private static PricingServiceFactory instance = new PricingServiceFactory(); private static IBondPricingService bondPricingService; private static IEquityPricingService equityPricingService; private PricingServiceFactory() { bondPricingService = BondPricingServiceFactory.CreateBondPricingService(); equityPricingService = EquityPricingServiceFactory.CreateEquityPricingService(); } public static IPricingService CreatePricingService() { DefaultPricingService ps = new DefaultPricingService (bondPricingService, equityPricingService); ps.Initialize(); return ps; } }
Summary of Traditional Approach • Meets design goals of interface based design • Issue: Being able to vs. being able to easily. • Switching implementations is difficult • Testing against stub implementation is difficult • Code up many factory classes • Pretty soon have dozens of them • What about non-trivial configuration • No object is an island – need to resolve collaborating objects • Classic ‘primitive’ data type configuration is often ad-hoc • maxResults, connectionString. Read in and parse .property files, xml etc. • Code noise infrastructure code unrelated to business logic • Tedious, Repetitive, Error Prone • Pushes you in the direction not to do it. • Takes discipline. • Can we do better?
Core Concepts – Inversion of Control • Inversion of Control (IoC) • Framework code is calling ‘your’ application code. • IoC applies to many areas • Messaging - Callback functions • Framework passes ‘Message’ object when available • Configuration management • Framework passes ‘Context’ to obtain references to other objects and services. • Framework calls your object’s properties directly. • Central design principal for other Spring modules • Data Access – Get passed IDbCommand with all resources managed by framework • Similar for other resource intensive APIs
“Pull Style” IoC for Configuration • Dependency Pull • Pull in dependencies and data as required • Object o = context.lookup(“string identifier”); • Looks like JNDI, Directory Service code • Contextualized Dependency Lookup • “Context” is pushed into your code by the framework. • Then pull in dependencies using the context • Context is a ‘generic factory’ • No need to write a factory class per object • The framework manages dependent object that is pulled in. • Lifecycle • Create, Configure, Initialize, Destroy, etc… • Typically via framework specific interfaces
“Push Style” IoC for Configuration • Dependency Injection • Object not responsible for looking up resources or dependencies. • An container creates objects and pushes configuration data/object dependencies into an object by reflection based calls to “standard” object constructor and/or properties • Setter Injection • Injection of dependencies via Properties • Constructor Injection • Injection of dependencies via constructor arguments • Method Injection • Container implements methods at runtime for lookup
Pull Style – Contextualized Dependency Lookup public interface IManagedComponent { voidPerformLookUp(Context context); } public class PortfolioManager : ManagedComponent { private ITradingService tradingService; public void PerformLookup(Context context) { tradingService = (ITradingService) context.GetObject( “bbTradingService” ); } public class BloombergTradingService : IInitialize, IOtherLifecycle { // normal implementation; constructor, properties, etc public void Initialize() { // allocate resources if necessary etc.. } }
Push Style - Dependency Injection public class PortfolioManager { private ITradingService tradingService; public ITradingService TradingService { get { return tradingService; } set { tradingService = value; } } } public class BloombergTradingService { // normal implementation; constructor, properties, etc public void Initialize() { // allocate resources etc.. } }
Example IoC Configuration <objects> <object name="..." type="..."> ... (properties and dependencies) </object> <object name="..." type="..." init-method="Initialize"> ... (properties and dependencies) </object> ... Other objects </objects>
IoC Bootstrapping • Usually get ‘top level’ object via IoC pull • Done in ‘main’ • All dependencies of top level object are ‘wired’ IApplicationContext ctx = ContextRegistry.GetContext(); PortfolioManager mgr = (PortfolioManager) ctx.GetObject (“myPortfolioManager"); Portfolio p = mgr.GetPortfolio(“ACCT123”);
IoC Externalized Configuration <objectname="myPortfolioManager" type="PricingDemo.PortfolioManager, PricingDemo"> <property name="TradingService" ref="myTradingService"/> <property name="PricingService" ref="myPricingService"/> </object> <object name="myTradingService" type="Bloomberg.TradingService, Bloomberg“> <property name="ConnectionString" value="http://nytrade01:5005"/> </object> <object name="myPricingService" type="PricingDemo.DefaultPricingService, PricingDemo"> <property name="BondPricingService" ref="myBondPricingService"/> <property name="EquityPricingService" ref="myEquityPricingService"/> </object>
IoC Externalized Configurition <object name="myBondPricingService" type="PricingDemo.DefaultPricingService, PricingDemo"> <property name="MarketDataService" ref="myMarketDataService"/> <property name="BondPricingAlgorithm" ref="basicBondPricingAlgorithm"/> </object> <object name="basicBondPricingAlgorithm" type="Algorithms.BasicBondPricer, Algorithms"/> <property name="Calendar" value="DEFAULT"/> </object> <object name="myMarketDataService" type="Reuters.MarketDataService, Reuters“ init-method=“init”> <property name="service" value="7500"/> <property name="network" value="lan1"/> <property name="daemon" value=""/> </object>
Dependency Injection Advantages • No lock-in to a particular framework APIs for configuration management • Application classes are self-documenting • Dependencies are explicit and always up-to-date • No ‘code-noise’ • Key piece of application plumbing is kept out of the way. • Promotes coding to interfaces • Strategy Pattern • Application classes are easier to test • General IoC advantage • Framework is responsible for reading configuration • Can switch where configuration comes from without changing application code • Greater consistency in configuration management.
IoC Summary • DI has gained a large following • Spring supports all types of IoC • Dependency Pull • Contextualized Lookup • Dependency Injection • Spring’s goal is to provide the most robust and feature rich IoC container • Singleton support, lazy initialization, support for traditional factory classes, … • Spring is not the only game in town – is part of a larger movement … • HiveMind, PicoContainer, SEAM, EJB3 • Castle, StructureMap, ObjectBuilder
Core Concepts - AOP • Another way to think about program structure • Apply common behavior across OO hierarchies • “Cross Cutting Concerns” • Introduce new behavior across OO hierarchies • “Mixins” • How can that behavior be applied and encapsulated? • Think “Decorator” on steroids in terms of functionality • Minimize code duplication • Non invasive to code – gives flexibility across an entire code base
Good Modularity • XML parsing in org.apache.tomcat • red shows relevant lines of code • nicely fits in one class
Poor Modularity • logging in org.apache.tomcat • red shows lines of code that handle logging • not in just one place • not even in a small number of places
Cross cutting concerns • Logging • entry/exit/exception to methods • Performance Metrics • Logging with timers • Observer design pattern • Caching Method return values • Security Checks • Monitoring • Alerts via email • WMI • Transaction Management
Core Concepts - AOP • Decorator • Can stick in code before a method executes, after it executes, and after it throws an exception • “Intercept” a method • AOP “Advice” Chain • Chained decorators. • AOP framework provides you with the means to • Define what code gets stuck in (Advice) • Before/After Returning/After Throwing • And where it can get stuck in (Pointcut) • Methods, Conditional Flow • Define the order of the chained advice.
Spring AOP • Spring.NET implements AOP by dynamically generating proxy classes at runtime. • Object obtained from a Spring IoC container can be transparently advised based on configuration • XML, Attributes. • Can also use programmatic API. • Out-of-box logging, pooling, caching, tx aspects • AOP Artifacts are also managed by container • Pointcuts – where to apply behavior • Methods invocation, Exception throwing. • Advice – what behavior to apply (Spring Terminology) • “AOP + IoC is a match made in heaven”
Spring AOP Example public interface ICommand { object Execute(object context); } public class ServiceCommand : ICommand { public object Execute(object context) { Console.Out.WriteLine("Service implementation : [{0}]", context); return null; } } public class ConsoleLoggingAroundAdvice : IMethodInterceptor { public object Invoke(IMethodInvocation invocation) { Console.Out.WriteLine("Advice executing; calling the advised method..."); object returnValue = invocation.Proceed(); Console.Out.WriteLine("Advice executed; advised method returned " + returnValue); return returnValue; } }
Creating and Executing a AOP Proxy ProxyFactory factory = new ProxyFactory(new ServiceCommand()); factory.AddAdvice(new ConsoleLoggingAroundAdvice()); ICommand command = (ICommand) factory.GetProxy(); command.Execute("This is the argument"); Advice executing; calling the advised method... Service implementation : [This is the argument] Advice executed; advised method returned
AOP Configuration Example • AutoProxy – Help apply AOP advice across objects in the IoC Container • ObjectNameAutoProxyCreator • Wildcards on object names • DefaultAdvisorAutoProxyCreator • Regular expression match on method name + advice <object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop"> <property name="ObjectNames"> <list> <value>English*</value> <value>PortugeseSpeaker</value> </list> </property> <property name="InterceptorNames"> <list> <value>debugInterceptor</value> </list> </property> </object>
Transaction Aspect public class TransactionInterceptor : TransactionAspectSupport, IMethodInterceptor { public object Invoke(IMethodInvocation invocation) { Type targetType = ( invocation.This != null ) ? invocation.This.GetType() : null; TransactionInfo txnInfo = CreateTransactionIfNecessary( invocation.Method, targetType ); object returnValue = null; try { returnValue = invocation.Proceed(); } catch ( Exception ex ) { DoCloseTransactionAfterThrowing( txnInfo, ex ); } finally { DoFinally( txnInfo ); } DoCommitTransactionAfterReturning( txnInfo ); return returnValue; } }
Attribute driven AOP • Attributes are used to define pointcut and provide the aspect configuration information public interface IAccountManager{ void DoTransfer(float creditAmount, float debitAmount); } public class AccountManager : IAccountManager { . . . [Transaction()] public void DoTransfer(float creditAmount, float debitAmount) { creditDao.CreateCredit(creditAmount); debitDao.DebitAccount(debitAmount); }
AOP Summary • What it is • Complementary to good OOP design • Solves problems that are difficult to solve with OOP • Leads to cleaner, better modularized code that is easier to maintain and extend. • What it is not • Experimental • Answer to all problems
Spring.NET/Java Comparison • bean->object • Ioc/AOP: Spring.NET = Spring.Java 1.2 • .NET has custom schema support but different than Spring.Java 2.0 • .NET has web scoped objects (Session/Application) .Java 2.0 • Spring.NET has ‘ConfigureObject’ • .NET specific • named constructor args • Indexers • Spring.Java has more breath • JMX, no WMI equivalent… • WebFlow • AspectJ’ized Spring.Java AOP • JMS – but coming soon to .NET • Expression Evaluation used for Property Name parsing.
Other functionality in Spring.Core • Spring.Expressions • Powerful expression language for manipulating an object at runtime • Think OGNL for C# • Spring.Validation • Validation based on expression language • Spring.Collections • ISet, thread-safe Set/Dictionary, PriorityQueue • Spring.Threading • LogicalTheadContext, Semaphore, Latch
Spring Expressions public class Inventor { public string Name; public string Nationality; public string[] Inventions; private DateTime dob; private Place pob; /// constructors omitted public DateTime DOB { get { return dob; } set { dob = value; } } public Place PlaceOfBirth { get { return pob; } } public int GetAge(DateTime on) { return on.Year - dob.Year; } }
Spring Expressions Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian"); tesla.PlaceOfBirth.City = "Smiljan"; string evaluatedName = (string) ExpressionEvaluator.GetValue(tesla, "Name"); string evaluatedCity = (string) ExpressionEvaluator.GetValue(tesla, "PlaceOfBirth.City")); ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.City", "Novi Sad");
Spring Expressions • Literals • ExpressionEvaluator.GetValue(null, "6.0221415E+23"); • Properties, Arrays, Lists, Dictionaries, Indexers • "Members[0].Inventions[6]") • Methods • "Members[0].GetAge(date('2005-01-01')" • Logical, Relational, Math Operations • "DateTime.Today <= date('1974-08-24')" • Variables IDictionary vars = new Hashtable(); vars["newName"] = "Mike Tesla"; ExpressionEvaluator.GetValue(tesla, "Name = #newName", vars); • If-then-else • Spring Object References "@MyMovieLister.MoviesDirectedBy('Roberto Benigni').Length
Spring.Services Features • Exports plain .NET objects (PONOs) as • Serviced Component, • Remote object • Web service • Exporters to connect .NET client to • RMI or EJB • Uses IIOP.NET library • Exported objects can be configured via Dependency Injection. • Apply aspects to exported objects using Spring.AOP • Isolates you from the changes in distributed technology
.NET Remoting Example • “Technology agnostic” calculator <object id="singletonCalculator" type="Services.AdvancedCalculator, Services"> <constructor-arg type="int" value="217" /> </object> • Export as a Singleton SAO <objects xmlns="http://www.springframework.net" xmlns:r="http://www.springframework.net/remoting"> <r:saoExporter targetName="singletonCalculator" serviceName="RemotedSaoSingletonCalculator" /> </object>
Spring Web • Extends ASP.NET • Enables Dependency Injection for ASP.NET web pages and controls • Enables bi-directional data binding • Greatly improves support for data validation • Adds localization support • Implements ‘result mapping’-based page flow • Adds Master Pages support to ASP.NET 1.1
Dependency Injection for ASP.NET • Uses custom IHttpHandlerFactory implementation to perform DI <object id="masterPage" type="~/Master.aspx" /> <object id="basePage" abstract="true"> <property name="Master" ref="masterPage"/> </object> <object type="TripForm.aspx" parent="basePage"> <property name="BookingAgent" ref="bookingAgent" /> <property name="AirportDao" ref="airportDaoProxy" /> <property name="TripValidator" ref="tripValidator" /> <property name="Results"> <dictionary> <entry key="displaySuggestedFlights" value="transfer:SuggestedFlights.aspx" /> </dictionary> </property> </object>
Spring Data Access • Provide uniform best practice approach across data access technologies. • IoC integration • Connection String management • Resource management • ‘Template’/callback APIs • Transaction management • Programmatic and declarative • Exception Translation • Added value • Make ‘native’ APIs easier to use • Higher level encapsulation of Data Access • DAO support classes, “AdoOperation” objects
Spring.NET Data Access • Spring.Java” users should feel right at home • ADO.NET, to first order • Java ported O/R Mappers, to second order. • ADO.NET framework • NHibernate support • iBatis.NET under development. • Early Adopter stage • Well hedged by “Spring.Java” design
Motivations for ADO.NET framework • Provide usable provider independent API • No factory in BCL (.NET 1.1) • Simplistic and at times incomplete interfaces • Easier parameter management • Exception Handling • Not singly rooted (.NET 1.1) • Base exception + error code (.NET 2.0) • No portable “DAO” exception hierarchy • Centralize Resource Management • Using is a great addition! No catch though. • Transaction management • Ad-hoc passing around of Transaction object • Still need to coordinate connections with TxScope